VueJs:使用Vuex进行表单处理和使用API​​生成的输入

时间:2018-02-28 11:34:11

标签: vue.js vuejs2 vue-component vuex

以下是组件的示例:

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

最后,返回API&#34; getModules&#34;的一个例子:

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

我的问题:改变&#34; isActive&#34;的最佳方式是什么?每个模块的属性为&#34; true&#34;当我选中与相关模块相对应的复选框时,直接在商店中

我知道Vuex的文档建议使用&#34; Two-way Computed Property&#34;管理表单,但在这里我不知道API可能返回的模块数量,而且我不知道他们的名字。

提前谢谢!

2 个答案:

答案 0 :(得分:1)

这是一个有点邪恶的方法,但它的工作原理。您可以为循环中访问的每个项目创建一个访问者对象:

&#13;
&#13;
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});
        }
      });
    }
  }
})
&#13;
<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>
&#13;
&#13;
&#13;

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

答案 1 :(得分:1)

我有替代解决方案。 你可以为复选框创建一个子组件来清理代码

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