VueJs:使用 Vuex 处理表单并使用 API 生成输入

VueJs: Form handling with Vuex and inputs generated with an API

这是一个组件示例:

<script>
    export default {
        name: 'my-form',

        computed: {
            myModules() {
                return this.$store.state.myModules;
            }
        }
</script>

<template>
    <form>
        <p v-for="module in myModules">
            <input type="checkbox" :value="module.id" />
            <label>module.name</label>
        </p>
        <button type="submit">Submit</button>
    </form>
</template>

关联店铺:

    state: {
        myModules: []
    },

    mutations: {
        setModules(state, modules) {
            state.myModules = modules;
        }
    },

    actions: {
        getModules({commit}) {
            return axios.get('modules')
            .then((response) => {
                commit('setModules', response.data.modules);
            });
        }
    }

最后,return 的 API "getModules" 的示例:

modules : [
    {
        id: 1,
        name: 'Module 1',
        isActive: false
    },
    {
        id: 2,
        name: 'Module 2',
        isActive: false
    },
    {
        id: 3,
        name: 'Module 3',
        isActive: false
    }
]

我的问题:当我选中与关联模块对应的复选框时,将每个模块的 "isActive" 属性 更改为 "true" 的最佳方法是什么,直接在店里?

我知道Vuex的文档推荐使用“Two-way Computed Property”来管理表单,但是我不知道API可以潜在的模块数量return ,我不知道他们的名字。

提前致谢!

这种方法有点邪恶,但很管用。您可以为循环中访问的每个项目创建一个访问器对象:

const store = new Vuex.Store({
  mutations: {
    setActive (state, {index, value}) {
      state.modules[index].isActive = value
    }
  },
  state: {
    modules : [
      {
        id: 1,
        name: 'Module 1',
        isActive: false
      },
      {
        id: 2,
        name: 'Module 2',
        isActive: false
      },
      {
        id: 3,
        name: 'Module 3',
        isActive: false
      }
    ]
  }
});
const app = new Vue({
  el: '#target',
  store,
  methods: {
    model (id) {
      const store = this.$store;
      // here i return an object with value property that is bound to 
      // specific module and - thanks to Vue - retains reactivity
      return Object.defineProperty({}, 'value', {
        get () {
          return store.state.modules[id].isActive
        },
        set (value) {
          store.commit('setActive', {index: id, value});
        }
      });
    }
  }
})
<script src="https://unpkg.com/vue/dist/vue.min.js"></script>
<script src="https://unpkg.com/vuex/dist/vuex.min.js"></script>
<div id="target">
  <div v-for="(item, id) in $store.state.modules">
    Module #{{ item.id }} state: {{ item.isActive }}
  </div>
  <div v-for="(item, id) in $store.state.modules">
    <label>
      Module #{{ item.id }}
      <input type="checkbox" v-model="model(id).value"/>
    </label>
  </div>
</div>

这仍然是一个相当混乱的方法,但至少你不必直接在模板中提交突变。在 Vue.set() 的一点帮助下,您甚至可以使用这种方法来克服标准反应性警告。

我为您提供了替代解决方案。 您可以为复选框制作一个子组件来稍微清理一下代码

UPD: 我刚刚意识到我和@etki 提出的所有建议都是矫枉过正。我在下面留下了旧版本的代码,以防您仍想看一看。这是一个新的:

const modules = [{
    id: 1,
    name: 'Module 1',
    isActive: true,
  },
  {
    id: 2,
    name: 'Module 2',
    isActive: false,
  },
  {
    id: 3,
    name: 'Module 3',
    isActive: false,
  },
];

const store = new Vuex.Store({
  state: {
    myModules: [],
  },
  mutations: {
    SET_MODULES(state, modules) {
      state.myModules = modules;
    },
    TOGGLE_MODULE(state, id) {
      state.myModules.some((el) => {
        if (el.id === id) {
          el.isActive = !el.isActive;
          return true;
        }
      })
    }
  },
  actions: {
    getModules({
      commit
    }) {
      return new Promise((fulfill) => {
        setTimeout(() => {
          commit('SET_MODULES', modules);
          fulfill(modules);
        }, 500)
      });
    }
  }
});

const app = new Vue({
  el: "#app",
  store,
  data: {},
  methods: {
    toggle(id) {
      console.log(id);
      this.$store.commit('TOGGLE_MODULE', id);
    }
  },
  computed: {
    myModules() {
      return this.$store.state.myModules;
    },
    output() {
      return JSON.stringify(this.myModules, null, 2);
    },
  },
  mounted() {
    this.$store.dispatch('getModules').then(() => console.log(this.myModules));
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vuex/3.0.1/vuex.js"></script>
<script src="https://unpkg.com/vue"></script>

<div id="app">
  <form>
    <div v-for="data in myModules">
      <label :for="data.id">{{ data.name }}: {{data.isActive}}</label>
      <input type="checkbox" :id="data.id" :name="'checkbox-' + data.id" :checked="data.isActive" @change="toggle(data.id)">
    </div>
  </form>
  <h3>Vuex state:</h3>
  <pre v-text="output"></pre>
</div>

正如您在上面看到的,您可以在输入更改时调用一个函数,并将 id 作为参数传递给触发 vuex 操作的方法。

The old version 我的代码。

A new one on jsfiddle