将 Vuex 与子组件一起使用的正确方法
Proper way to use Vuex with child components
我以前用过VueJS和Vuex。不在生产中,仅用于一些简单的个人副项目,感觉非常简单。
然而,现在我面临一个稍微复杂一点的问题,但使用 Vuex 已经感觉更复杂了。所以我在这里寻找一些指导。
在主视图中,我向用户显示了卡片列表。卡片是大约十个属性(输入、选择等)的可编辑形式。我显然为这些卡片实现了一个组件,因为它们在列表视图中重复出现。我的第一个天真的方法是从我的商店中获取一个列表 - 让我们称之为表单 - 然后使用 v-for
为该表单列表中的每个表单呈现一张卡片。表单作为 属性.
传递给子组件
现在我想将表单控件绑定到属性。为此,我实施了 Two-way Computed Properties 以正确利用我的商店突变。但是,使用 getter 和 setter 为我的模型中的每个 属性 加上变异实现自定义计算 属性 感觉非常重复。此外,表格是我所在州的一个数组。所以我必须将要在商店中编辑的表单的 ID 传递给每个突变。
我想到的其他事情只是将表单的商店 ID 传递给子组件,并为我的模型的每个 属性 提供“by id”getters 以及匹配突变。但这也不是执行此操作的正确方法。本质上是一样的吧?!
这个问题有更好的解决办法吗?也许我只是遗漏了一些东西,或者我把事情复杂化了。
精简示例:
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.
如果有人想探究这个有趣的失败,see here)
要解决此问题,您可以使用手表和数据克隆:
<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);
}
}
这比它应该需要的要复杂得多......但它有效。
我以前用过VueJS和Vuex。不在生产中,仅用于一些简单的个人副项目,感觉非常简单。
然而,现在我面临一个稍微复杂一点的问题,但使用 Vuex 已经感觉更复杂了。所以我在这里寻找一些指导。
在主视图中,我向用户显示了卡片列表。卡片是大约十个属性(输入、选择等)的可编辑形式。我显然为这些卡片实现了一个组件,因为它们在列表视图中重复出现。我的第一个天真的方法是从我的商店中获取一个列表 - 让我们称之为表单 - 然后使用 v-for
为该表单列表中的每个表单呈现一张卡片。表单作为 属性.
现在我想将表单控件绑定到属性。为此,我实施了 Two-way Computed Properties 以正确利用我的商店突变。但是,使用 getter 和 setter 为我的模型中的每个 属性 加上变异实现自定义计算 属性 感觉非常重复。此外,表格是我所在州的一个数组。所以我必须将要在商店中编辑的表单的 ID 传递给每个突变。
我想到的其他事情只是将表单的商店 ID 传递给子组件,并为我的模型的每个 属性 提供“by id”getters 以及匹配突变。但这也不是执行此操作的正确方法。本质上是一样的吧?!
这个问题有更好的解决办法吗?也许我只是遗漏了一些东西,或者我把事情复杂化了。
精简示例:
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.
如果有人想探究这个有趣的失败,see here)
要解决此问题,您可以使用手表和数据克隆:
<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);
}
}
这比它应该需要的要复杂得多......但它有效。