将 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);
  }
}

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