在 Vuex store 中处理表单

当我们在 Vue 应用程序中使用 v-model 进行双向数据绑定时,Vue 实例中的数据会与 v-model 输入字段同步。因此,当你在输入字段中键入任何内容时,数据会立即更新。然而,这会在 Vuex store 中产生一个问题,因为我们不能在 mutations 属性之外修改 storestate(数据)。让我们看一个 Vuex store 中简单的双向数据绑定示例:

// vuex-non-sfc/handling-forms/v-model.html
<div id="demo">
  <input v-model="user.message" />
  <p>Message: {{ user.message }}</p>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuex@3.6.2/dist/vuex.js"></script>

<script type="text/javascript">
const store = new Vuex.Store({
  strict: true,
  state: {
    user: {
      message: ''
    }
  }
})

new Vue({
  el: '#demo',
  store: store,
  computed: {
    user () {
      return this.$store.state.user
    }
  }
})
</script>

对于这个示例,当你在输入字段中键入消息时,你将在浏览器的调试工具中看到以下错误消息:

Error: [vuex] do not mutate vuex store state outside mutation handlers.

这是因为当你键入时,v-model 尝试直接修改 store state 中的 message,因此在严格模式下会导致错误。让我们在接下来的章节中看看我们有哪些选项可以解决这个问题。

使用 v-bind 和 v-on 指令

在大多数情况下,双向绑定并不总是合适的。在 Vuex 中,使用单向绑定和显式数据更新通过将 <input> 绑定到 value 属性和 change 事件上更有意义。你可以通过以下步骤轻松实现此操作:

  1. 就像你在前面的章节中学到的那样,在 mutations 属性中创建一个用于修改 state 的方法:

    // vuex-sfc/form-handling/value-event/store/index.js
    import Vue from 'vue'
    import Vuex from 'vuex'
    
    Vue.use(Vuex)
    
    export default new Vuex.Store({
      strict: true,
      state: {
        message: ''
      },
      mutations: {
        updateMessage (state, message) {
          state.message = message
        }
      }
    })
  2. <input> 元素绑定到 value 属性,并将 input 事件绑定到方法,如下所示:

    // vuex-sfc/form-handling/value-event/components/app.vue
    <template>
      <input v-bind:value="message" v-on:input="updateMessage" />
      <p>Message: {{ message }}</p>
    </template>
    
    <script>
    import { mapState } from 'vuex'
    
    export default {
      computed: {
        ...mapState({
          message: state => state.message
        })
      },
      methods: {
        updateMessage (e) {
          this.$store.commit('updateMessage', e.target.value)
        }
      }
    }
    </script>

在这个解决方案中,我们使用子组件中的 updateMessage 方法来提交 store 中的 mutation 方法 updateMessage,并传递来自 input 事件的值。通过像这样只显式地提交 mutation,我们没有违反 Vuex 中必须遵守的强制规则。因此,采用这种解决方案意味着你不能使用 v-model 来处理 Vuex store 的表单。然而,如果你使用 Vue 本身的计算属性的 gettersetter,你仍然可以使用它。让我们在下一节中介绍这一点。

使用双向计算属性

我们可以借助以下步骤,使用 Vue 内置的带 setter 的双向计算属性来处理带有 v-model 的表单:

  1. 就像上一节一样,在 mutations 属性中创建一个用于修改 state 的方法。

  2. getset 方法应用于 message 键,如下所示:

// vuex-sfc/form-handling/getter-setter/components/app.vue
<template>
  <input v-model="message" />
  <p>Message: {{ message }}</p>
</template>

<script>
export default {
  computed: {
    message: {
      get () {
        return this.$store.state.message
      },
      set (value) {
        this.$store.commit('updateMessage', value)
      }
    }
  }
}
</script>

然而,这可能适用于简单的计算属性。如果你有一个超过 10 个键的深层对象需要更新,你将需要 10 组双向计算属性(gettersetter)。与基于事件的解决方案相比,代码最终会变得更加重复和冗长。

做得好!你已经成功掌握了 Vuex store 的基础和概念。你已经学习了如何在 Vue 应用程序中使用 store。现在,是时候继续在 Nuxt 中应用 store 了。让我们在下一节中开始吧。

如果你想了解更多关于 Vuex 的信息,请访问 https://vuex.vuejs.org/