从 vuex 状态数组生成计算属性数组以用于 v-model

Posted

技术标签:

【中文标题】从 vuex 状态数组生成计算属性数组以用于 v-model【英文标题】:make array of computed properties from vuex state array for use in v-model 【发布时间】:2022-01-08 07:48:14 【问题描述】:

我在 Vue 3 中有以下设置。

将数组作为状态一部分的 vuex 存储:

const store = createStore(
  state: 
    questions: [
       text: 'A', value: false ,
       text: 'B', value: false ,
       text: 'C', value: true ,
    ],
  ,
  mutations: 
    updateQuestionValue(state,  index, value ) 
      state.questions[index].value = value;
    ,
  ,
);

还有一个组件,它试图呈现一个复选框列表,该列表应该对应于 state 中的“questions”数组。

<template>
    <div v-for="(question, index) in questions">
        <label :for="'q'+index">question.text</label>
        <input :id="'q'+index" v-model="questionComputeds[index]" type="checkbox" />
    </div>
</template>

<script setup>
import  computed  from 'vue';
import  useStore  from 'vuex';

const store = useStore();

const questions = computed(() => store.state.questions);

const questionComputeds = store.state.questions.map((q, i) =>
    computed(
        get() 
             return store.state.questions[i].value;
        ,
        set(value) 
             store.commit('updateQuestionValue',  index: i, value );
        ,
    )
);
</script>

如您所见,我希望使用 v-model 为列表中的每个输入元素制定两种方式的绑定,但是因为我将 vuex 与数组一起使用,所以我想在我的计算中使用 get/set 选项属性并使用模板中的索引访问特定的计算。但是我发现这不起作用。它不会引发错误,但也无法将复选框的值绑定到我的问题对象中的 .value 道具。我对这里的策略完全不了解吗?你甚至可以像.map() 那样制作“计算”数组吗?有什么方法可以将 v-model 与这种数据结构一起使用?

【问题讨论】:

【参考方案1】:

第一个问题:

在模板的第一行

&lt;div v-for="(question, index) in questions"&gt;

questions 未定义。可以换成

&lt;div v-for="(question, index) in questionComputeds"&gt;

或者在创建时传递给 store 的 questions 可以被提取到一个变量中,在你的组件中导出和导入

第二个问题:

您的第二行缺少.value

应该是

&lt;input v-model="questionComputeds[index].value" type="checkbox" /&gt;

这两个更改应该可以解决它。考虑到你不需要 v-for 中的索引,你得到了

完整解决方案:
<template>
  <div v-for="question in questionComputeds">
    <input v-model="question.value" type="checkbox" />
  </div>
</template>

<script setup>
import  computed  from 'vue';
import  useStore  from 'vuex';

const store = useStore();

const questionComputeds = store.state.questions.map((q, i) =>
    computed(
      get: () => store.state.questions[i].value,
      set: (value) =>  store.commit('updateQuestionValue',  index: i, value ) ,
    )
);
</script>

替代方案:

简单的解决方案:
<template>
  <div v-for="(question, index) in questionComputeds">
    <input :checked="questionComputeds[index]" type="checkbox" @input="handleChange(index, $event)" />
  </div>
</template>

<script setup>
import  computed  from 'vue';
import  useStore  from 'vuex';

const store = useStore();

const handleChange = (i, e) => 
  store.commit('updateQuestionValue',  index: i, value: e.target.checked );
  // to verify:
  // console.log( ...store.state.questions[i] );


const questionComputeds = computed(() => store.state.questions.map(q => q.value))

</script>
更复杂(但更可重用)的解决方案:

将您的复选框数组提取到单独的组件并定义自定义v-model

【讨论】:

我已经习惯了.value 在 SFC 的 另外,对于questions 的值的遗漏,我感到很抱歉,这只是我的疏忽。在我的实际(非最小可重现示例)代码中,它被包含为它自己从 vuex 存储中计算出来的,并且是必要的,因为我使用它来填充 一起使用 回答您关于.value的问题。我认为理解这一点的最佳方法是将商店条目的道具重命名(只是尝试当然可以撤消它),例如 text: 'A', booleanValue: false 。然后您将看到您必须将v-model="question.value" 更改为v-model="question.booleanValue"get: () =&gt; store.state.questions[i].value 更改为get: () =&gt; store.state.questions[i].booleanValue。这表明.value 与 Vue 的“通过代理的反应性”实现无关。这是您提供给 questions 的 prop 密钥的名称。 如果您不仅可以投票还可以接受答案,那就太好了,因为它不仅仅是完整的恕我直言;-) 您的回复完全有道理,感谢您的解决

以上是关于从 vuex 状态数组生成计算属性数组以用于 v-model的主要内容,如果未能解决你的问题,请参考以下文章

哪种方法将元素添加到 Vuex 状态属性的数组属性是正确的?

使用 Vuex getter 进行 Vuetify Select

Vuex 状态下的重复数组项(使用 Socket.io)

如何循环遍历传递给具有 Vuex 存储和计算属性的组件的对象数组?

Vue V-用于将数组绑定到错误的组件

v-if 没有在计算属性上触发