我有一个系统,它使用许多表单组件根据输入的信息实时更新视图。当我第一次构建应用程序时,我主要使用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)
}
},
答案 0 :(得分:1)
实际上,两种方式都是错误的。将strict: true
添加到您的商店,您会在两种情况下都看到错误。
在两种选择中,prof
的{{1}},name
和email
属性都会被直接修改(这违反了规定每项变更的Vuex原则应该通过突变发生。)
同样地,不是那个计算的setter(第一种情况),也不是那个观察者(第二种情况)被触发,因为你没有修改office
,而是深深嵌套它的属性(例如{{1} })。
最简单的解决方案,即允许你使用mixin ,就是放弃item
并使用name
和v-model
绑定。例如:
:value
请注意,它使用@input
方法,该方法提交变异(见下文)并进入mixin。
这样所有修改都在突变中完成。最后要注意的是,如果您使用<textarea :value="prof.name" @input="updateProf(prof, 'name', $event)" >
和updateProf
详细信息,则可以创建custom directive来处理它。
JSFiddle link或演示(相同代码)。
:value
&#13;
@input
&#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。演示(与小提琴相同的代码)如下:
v-model
&#13;
v-model
&#13;