更新子组件内的道具,使其也在父容器上更新
Posted
技术标签:
【中文标题】更新子组件内的道具,使其也在父容器上更新【英文标题】:Updating a prop inside a child component so it updates on the parent container too 【发布时间】:2019-01-27 23:57:39 【问题描述】:所以我有一个像这样的简单模板:
<resume-index>
<div v-for="resume in resumes">
<resume-update inline-template :resume.sync="resume" v-cloak>
//...my forms etc
<resume-update>
</div>
<resume-index>
现在,在resume-update
component 内部,我正在尝试更新内部的道具,以便外部不会被覆盖,我的代码就是这样;
import Multiselect from "vue-multiselect";
import __ from 'lodash';
export default
name: 'resume-update',
props: ['resume'],
components:
Multiselect
,
data: () => (
form:
name: '',
level: '',
salary: '',
experience: '',
education: [],
employment: []
,
submitted:
form: false,
destroy: false,
restore: false
,
errors: []
),
methods:
update(e)
this.submitted.form = true;
axios.put(e.target.action, this.form).then(response =>
this.resume = response.data.data
this.submitted.form = false;
).catch(error =>
if (error.response)
this.errors = error.response.data.errors;
this.submitted.form = false;
);
,
destroy()
this.submitted.destroy = true;
axios.delete(this.resume.routes.destroy).then(response =>
this.resume = response.data.data;
this.submitted.destroy = false;
).catch(error =>
this.submitted.destroy = false;
)
,
restore()
this.submitted.restore = true;
axios.post(this.resume.routes.restore).then(response =>
this.resume = response.data.data;
this.submitted.restore = false;
).catch(error =>
this.submitted.restore = false;
)
,
reset()
for (const prop of Object.getOwnPropertyNames(this.form))
delete this.form[prop];
,
watch:
resume: function()
this.form = this.resume;
,
,
created()
this.form = __.cloneDeep(this.resume);
当我提交表单并更新 this.resume
时,我得到以下信息:
[Vue 警告]:避免直接改变一个 prop,因为它的值会是 每当父组件重新渲染时被覆盖。相反,使用 基于道具值的数据或计算属性。道具存在 变异:“简历”
我尝试将计算添加到我的文件中,但这似乎不起作用:
computed:
resume: function()
return this.resume
那么,我该如何更新道具呢?
【问题讨论】:
不要更新道具。使用 $emit 将事件发回给父级。 【参考方案1】:一种解决方案:
模拟v-model
作为 Vue Guide said:
v-model 本质上是用于更新用户输入数据的语法糖 事件,以及对一些边缘情况的特殊照顾。
语法糖如下:
directive=v-model
将绑定值,然后监听input
事件以进行更改,如v-bind:value="val" v-on:input="val = $event.target.value"
那么步骤:
创建一个你想同步到父组件的 prop = value
在子组件内部,创建一个数据端口=internalValue,然后使用Watcher将最新的prop=value
同步到data property=intervalValue
如果intervalValue
发生变化,发出一个输入事件来通知父组件
下面是一个简单的演示:
Vue.config.productionTip = false
Vue.component('container',
template: `<div>
<p><button @click="changeData()">value</button></p>
</div>`,
data()
return
internalValue: ''
,
props: ['value'],
mounted: function ()
this.internalValue = this.value
,
watch:
value: function (newVal)
this.internalValue = newVal
,
methods:
changeData: function ()
this.internalValue += '@'
this.$emit('input', this.internalValue)
)
new Vue(
el: '#app',
data ()
return
items: ['a', 'b', 'c']
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app">
<div>
<p>items
<container v-for="(item, index) in items" :key="index" v-model="items[index]">
</container>
</div>
</div>
或使用其他道具名称代替值(以下演示使用道具名称=item):
您也可以使用其他事件名称代替事件名称=输入。
其他步骤类似,但您必须在事件上 $on 然后实现您自己的处理程序,如下面的演示。
Vue.config.productionTip = false
Vue.component('container',
template: `<div>
<p><button @click="changeData()">item</button></p>
</div>`,
data()
return
internalValue: ''
,
props: ['item'],
mounted: function ()
this.internalValue = this.item
,
watch:
item: function (newVal)
this.internalValue = newVal
,
methods:
changeData: function ()
this.internalValue += '@'
this.$emit('input', this.internalValue)
this.$emit('test-input', this.internalValue)
)
new Vue(
el: '#app',
data ()
return
items: ['a', 'b', 'c']
,
methods:
syncChanged: function (target, index, newData)
this.$set(target, index, newData)
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app">
<div>
Event Name=input
<p>items</p>
<container v-for="(item, index) in items" :key="index" :item="item" @input="syncChanged(items, index,$event)">
</container>
</div>
<hr> Event Name=test-input
<container v-for="(item, index) in items" :key="index" :item="item" @test-input="syncChanged(items, index,$event)">
</container>
</div>
【讨论】:
【参考方案2】:我通常使用vuex
来管理我将在多个组件中使用的变量,就像错误所说的那样,使用计算属性将它们加载到各个组件中。然后使用store对象的mutations属性来处理变化
在组件文件中
computed:
newProfile:
get()
return this.$store.state.newProfile;
,
set(value)
this.$store.commit('updateNewProfile', value);
,
在 vuex 商店中
state:
newProfile:
Name: '',
Website: '',
LoginId: -1,
AccountId: ''
,
mutations:
updateNewProfile(state, profile)
state.newProfile = profile;
【讨论】:
这也是我最近发现自己在做的事情。可能有更好的方法来做到这一点,但我不知道。 如果它只是父子数据,他们应该使用事件发射器。 Vuex 更多的是服务于全局状态,而不仅仅是简单的父子数据突变以上是关于更新子组件内的道具,使其也在父容器上更新的主要内容,如果未能解决你的问题,请参考以下文章