Vuex form表单处理, 比官网更好的办法

Vuex form表单处理, 比官网更好的办法

问题, 当使用vuex的state作为表单的v-model元素, 虽然简单粗暴, 但这种修改没有经过mutation方法. 在严格模式下会抛出错误

1. 错误提示

错误代码如下

[Vue warn]: Error in callback for watcher “function () { return this._data.$$state }”: “Error: [vuex] do not mutate vuex store state outside mutation handlers.”

2. 相关场景

vuex中相关代码

const state = ()=>({
  user: {
    username: '123',
    password: '123',
  }
});

const getters = {
  userName: state=>state.userName,
  user: state=>state.user,
};

const mutations = {
  changeObject(state, payload){
    // es6语法
    state.user = {...state.user, ...payload};
  },
};

其中定义了user变量

组件中相关代码

// 获取vuex中user
...mapGetters('module1', [
    'user',
]),
// 改变vuex中user状态
...mapMutations('module1', [
    'changeObject',
]),
    

3. 官网建议方法

  • <input> 中绑定 value,然后侦听 input 或者 change 事件,在事件回调中调用一个方法
  • 另一个方法是使用带有 setter 的双向绑定计算属性
// ...
computed: {
  message: {
    get () {
      return this.$store.state.obj.message
    },
    set (value) {
      this.$store.commit('updateMessage', value)
    }
  }
}

这两种方法都有一种很大的缺陷, 必须定义每个输入元素的变量, 比如, 现在有个表单, 里面有20个元素, 那么此时就要写20个方法来响应输入框的变化, 作为工匠人, 不得不采取更好的办法


4. 解决方案

个人在网上找了一些解决方案, 有用proxy代理, 有封装一些方法的, 这些在我看来, 都挺勉强的

经过一系列尝试, 我改良了官网描述的第二种方法, 将表单元素与vuex双向绑定, 并且经过了mutation, 严格模式下不报错

核心代码如下

定义表单对象

// 定义在computed下
object: {
 set(val){
   // console.log(val);
   this.changeObject(val);
 },
  //这里需要注意, 获取的是user信息, 并非对象, 采用扩展运算符处理
  get(){
   return {...this.user}
  }
}

获取表单变化代码

<form :model="object" @input="inputChange">
  <input type="text" v-model="object.username">
  <input type="text" v-model="object.password">
</form>

// ... methods中方法
inputChange(){
  this.object = {...this.object}
},


5. 整体解释

  1. vuex定义username和password
  2. object 通过 get 获取到username和password进行初始化
  3. 表单输入触发inputChange方法改变 object 对象, 触发object对象的 set 方法
  4. object的 set 方法改变了 vuex中的值
  5. vuex 值发生改变, 从而触发 object 的 get 方法
  6. object值发生改变, 从而形成一个循环链
graph TD;
A(vuex定义变量) –> B(初始化表单object)
B –> C(表单输入触发inputChange方法)
C –> D(inputChange触发object的set方法)
D –> E(object的set方法改变vuex中的状态变量)
E –> F(vuex状态变化触发object的get方法)

  1. 初始状态

  1. 改变username后的状态

image-20201125204440609

  1. 改变password后的状态