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後的狀態