在 Vuex 中的对象数组上使用 v-bind

Mat*_*ias 3 vuex vuejs2

我正在尝试将用户输入从表单绑定到我的 vuex 商店中的状态。

状态看起来像这样:

customers: [
  {firstName: "", lastName: "", age: ""},
  {firstName: "", lastName: "", age: ""},
  {firstName: "", lastName: "", age: ""}
]
Run Code Online (Sandbox Code Playgroud)

我尝试在调用 get 和 set 方法的计算属性上使用 v-model 。我在这里找到了解释。

这对于对象来说非常有效,但不幸的是没有解释如何在对象数组上使用它。

我正在寻找这样的东西:

computed: {
  firstName: {
    get () {
      return this.$store.state.customers[i].firstName
    },
    set (value) {
      this.$store.commit('changeFirstname', {value, index})
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

但显然这不起作用,因为我无法将索引传递给计算属性。有人对此有解决方案吗?对于深度观察者来说,这是一个很好的用例吗?

这是我的第一个问题,如果我忘记了什么或者做错了什么,请告诉我,以便我改进我的提问。谢谢!

ski*_*tle 5

当你的数据不平坦时,Vuex 可能会有点麻烦。有关更多信息,请参阅https://forum.vuejs.org/t/vuex-best-practices-for-complex-objects/10143 。

解决这个问题的一种方法是放弃v-model并直接使用:valueand @input。我在示例中模拟了一家商店,但希望大家清楚发生了什么。如果您发现比传递对象本身更容易,则可以轻松获取客户的索引。

const storeCustomers = Vue.observable([
  {firstName: "A", lastName: "", age: ""},
  {firstName: "B", lastName: "", age: ""},
  {firstName: "C", lastName: "", age: ""}
])

function storeGetCustomers () {
  return storeCustomers
}

function storeUpdateCustomerFirstName (customer, value) {
  customer.firstName = value
}

new Vue({
  el: '#app',
  
  computed: {
    customers () {
      return storeGetCustomers()
    }
  },
  
  methods: {
    onFirstNameInput (customer, value) {
      storeUpdateCustomerFirstName(customer, value)
    }
  }
})
Run Code Online (Sandbox Code Playgroud)
<script src="https://unpkg.com/vue@2.6.10/dist/vue.js"></script>
<div id="app">
  <div v-for="customer in customers">
    <input :value="customer.firstName" @input="onFirstNameInput(customer, $event.target.value)">
  </div>
  <p>
    {{ customers }}
  </p>
</div>
Run Code Online (Sandbox Code Playgroud)

保留的另一种选择v-model是引入一个单独的组件来保留每个客户。一般来说,当用于涉及v-for编辑的任何内容时,值得考虑引入新组件。

在此示例中存在不对称性,因为从父级中的商店读取客户并将其写入子级中的商店。我觉得有点不舒服。也许如果每个客户都有一个 id,那么该 id 可以作为 prop 而不是客户对象传递给子级,让子级获取和设置它感兴趣的单个客户。

const storeCustomers = Vue.observable([
  {firstName: "A", lastName: "", age: ""},
  {firstName: "B", lastName: "", age: ""},
  {firstName: "C", lastName: "", age: ""}
])

function storeGetCustomers () {
  return storeCustomers
}

function storeUpdateCustomerFirstName (customer, value) {
  customer.firstName = value
}

const child = {
  props: ['customer'],
  
  template: `
    <div>
      <input v-model="firstName">
    </div>
  `,
  
  computed: {
    firstName: {
      get () {
        return this.customer.firstName
      },
      
      set (value) {
        storeUpdateCustomerFirstName(this.customer, value)
      }
    }
  }
}

new Vue({
  el: '#app',
  
  components: {
    child
  },
  
  computed: {
    customers () {
      return storeGetCustomers()
    }
  }
})
Run Code Online (Sandbox Code Playgroud)
<script src="https://unpkg.com/vue@2.6.10/dist/vue.js"></script>
<div id="app">
  <child v-for="customer in customers" :customer="customer"></child>
  <p>
    {{ customers }}
  </p>
</div>
Run Code Online (Sandbox Code Playgroud)

对于您关于深度观察者的问题,我相信您所描述的内容将涉及改变商店外的状态,然后让观察者让商店知道这一点。实际上商店不需要做任何事情,因为状态已经改变了。显然,这会违反关于仅改变 store 内部的 store 状态的“规则” mutations