将Vuex与子组件一起使用的正确方式



我以前使用过VueJS和Vuex。不是在制作中,只是一些简单的个人副业,感觉很直接。

然而,现在我面临的问题稍微复杂一点,但使用Vuex已经感觉复杂多了。所以我在这里寻求一些指导。

在主视图中,我向用户展示了一张卡片列表。卡片是一种可编辑的形式,大约有十个属性(输入、选择等(。我显然为这些卡片实现了一个组件,因为它们在列表视图中重复。我的第一个天真的方法是从我的商店中获取一个表单列表,然后使用v-for为该表单列表中的每个表单提供一张卡片。表单作为属性传递给子组件。

现在我想将表单控件绑定到属性。为了做到这一点,我实现了双向计算属性,以正确利用我的存储突变。但是,用getter和setter为模型上的每个属性实现一个自定义计算属性,再加上突变,感觉非常重复。此外,表单在我的状态下是一个数组。所以我必须将要在商店中编辑的表单的id传递给每个突变。

我想到的另一件事就是将表单的存储id传递给子组件;通过id";我的模型的每个属性的getter以及匹配的突变。但这也不是正确的方式。本质上是一样的,对吧?!

这个问题有更好的解决办法吗?也许我只是错过了什么,或者我把事情搞得太复杂了。

一个精简的例子:

Editor.vue:

<template>
<v-container>
<EditableCard v-for="(card, i) in cards" :key="i" :card="card" />
</v-container>
</template>
<script>
import EditableCard from "@/components/EditableCard";
import { mapGetters } from "vuex";
export default {
name: "Editor",
components: {
EditableCard
},
computed: {
...mapGetters("cards", {
cards: "list"
})
}
};
</script>

EditableCard:

<template>
<v-card>
<v-form>
<v-card-title>
<v-text-field v-model="title"></v-text-field>
</v-card-title>
<v-card-text>
<v-text-fieldv-model="text"></v-text-field>
<!-- And some more fields... -->
</v-card-text>
</v-form>
</v-card>
</template>
<script>
import { mapMutations } from "vuex";
export default {
name: "EditableCard",
props: {
card: Object
},
computed: {
title: {
get() {
return card.title;
},
set(value) {
this.setCardTitle(this.card.id, value);
}
},
text: {
get() {
return card.text;
},
set(value) {
this.setCardText(this.card.id, value);
}
}
// Repeat for every form input control
},
methods: {
...mapMutations("cards", {
setCardTitle: "setTitle",
setCardText: "setText"
// Repeat for every form input control
})
}
};
</script>

使用克隆为整个表单对象创建一个计算setter会很好,但这不会起作用,因为更改不会触发计算setter。

如果有人想探索这个有趣的失败,请参阅此处(

要解决此问题,您可以使用手表和数据克隆:

<v-form>
<v-text-field v-model="clone.title" />
<v-text-field v-model="clone.text" />
</v-form>
props: ['index', 'card'],
data() {
return {
clone: {}
}
},
watch: {
card: {
handler(card) {
this.clone = { ...card }
},
immediate: true,
deep: true
},
clone: {
handler(n,o) {
if (n === o) {
this.$store.commit('SET_CARD', { index: this.index, card: n })
}
},
deep: true
}
}

您的v-for:

<EditableCard v-for="(card, index) in cards" :card="card" :index="index" :key="index" />

突变:

mutations: {
SET_CARD(state, { index, card }) {
Vue.set(state.cards, index, card);
}
}

这比它应该需要的要复杂得多……但它是有效的。

相关内容

最新更新