未在Vuex

时间:2018-03-29 22:01:40

标签: javascript vue.js local-storage vuex

我有一个系统,它使用许多表单组件根据输入的信息实时更新视图。当我第一次构建应用程序时,我主要使用v-model,本地组件数据和vue save状态来将数据保存在本地存储中,以便在重新加载页面时保持不变。

然而,当我在程序扩展时转移到vuex时,这并不是那么简单,所以我决定使用带有getter和setter的计算属性的v-model,所以我不必为超过50种不同的更改函数编写投入。我还意识到你可以为一个对象创建一个计算变量,并且仍然使用v-model来访问和更新该对象的属性,如下所示:

  <div v-for="prof in info.profs">
  <textarea v-model="prof.name" class="code-input uk-input" rows="1" cols="20"></textarea>
  <textarea v-model="prof.email" class="code-input uk-input" rows="1" cols="25"></textarea>
  <textarea v-model="prof.office" class="code-input uk-input" rows="1" cols="50"></textarea> <br>
  </div>

info: {
  get () {
    return this.$store.getters.getInfo
  },
  set (payload) {
    this.$store.commit('updateInfo', payload)
  }
},

这很好用,商店更新每个属性的数据而不必创建自己独立的计算变量,但由于某种原因,它不会在vue chrome dev工具上显示为已提交的变异“updateInfo”当我为vuex使用本地存储插件(如vuex-persistedstate或vuex-persist)时,它不会更改本地存储数据,直到我提交另一个正常结构的突变。现在我的解决方法是在组件中创建属性的本地副本,然后观察该属性的更改并提交到商店,这让我可以再次使用组件级别localstorage mixin,但我觉得必须有更好的执行此操作的方法不涉及为info中的每个属性编写更改函数或计算变量,因为在此应用程序中这将非常详细。

data () {
return {
  info: this.$store.getters.getInfo
 }
},
watch: {
info: function(payload){
  this.$store.commit('updateInfo', payload)
 }
},

1 个答案:

答案 0 :(得分:1)

实际上,两种方式都是错误的。将strict: true添加到您的商店,您会在两种情况下都看到错误。

在两种选择中,prof的{​​{1}},nameemail属性都会被直接修改(这违反了规定每项变更的Vuex原则应该通过突变发生。)

同样地,不是那个计算的setter(第一种情况),也不是那个观察者(第二种情况)被触发,因为你没有修改office,而是深深嵌套它的属性(例如{{1} })。

最简单的解决方案,即允许你使用mixin ,就是放弃item并使用namev-model绑定。例如:

:value

请注意,它使用@input方法,该方法提交变异(见下文)并进入mixin。

这样所有修改都在突变中完成。最后要注意的是,如果您使用<textarea :value="prof.name" @input="updateProf(prof, 'name', $event)" > updateProf详细信息,则可以创建custom directive来处理它。

JSFiddle link或演示(相同代码)。

&#13;
&#13;
:value
&#13;
@input
&#13;
&#13;
&#13;

保持const store = new Vuex.Store({ strict: true, state: { info: { profs: [ {name: "Alice", email: "alice@example.com", office: "NY"}, {name: "Bob", email: "bob@example.com", office: "CA"} ] } }, mutations: { updateProf(state, {prof, prop, value}) { prof[prop] = value; } }, getters: { getInfo: state => { return state.info } } }); const mixin = { computed: { info() { return this.$store.getters.getInfo } }, methods: { updateProf(prof, prop, e) { this.$store.commit('updateProf', {prof, prop, value: e.target.value}) } } } new Vue({ store, mixins: [mixin], el: '#app' })

就是这样,没有人告诉我没有说这是可能的,这是继续使用<script src="https://unpkg.com/vue"></script> <script src="https://unpkg.com/vuex"></script> <div id="app"> {{ info }} <div v-for="prof in info.profs"> <hr> name: <textarea :value="prof.name" @input="updateProf(prof, 'name', $event)" class="code-input uk-input" rows="1" cols="20"></textarea> <br> email: <textarea :value="prof.email" @input="updateProf(prof, 'email', $event)" class="code-input uk-input" rows="1" cols="25"></textarea> <br> office: <textarea :value="prof.office" @input="updateProf(prof, 'office', $event)" class="code-input uk-input" rows="1" cols="50"></textarea> </div> </div>的一种方法。这个替代方案的关键点是深度克隆和深度克服的功能。我提供了两个简单/天真的实现,YMMV:

JSFiddle link。演示(与小提琴相同的代码)如下:

&#13;
&#13;
v-model
&#13;
v-model
&#13;
&#13;
&#13;