更新子组件内的道具,以便它也在父容器上更新 [英] Updating a prop inside a child component so it updates on the parent container too
问题描述
所以我有一个像这样的简单模板:
<div v-for="简历中的简历"><resume-update inline-template :resume.sync="resume" v-cloak>//...我的表格等<恢复更新>
<简历索引>
现在,在 resume-update
组件中,我试图更新内部的 prop,这样外部就不会被覆盖,我的代码就是这样;
从vue-multiselect"导入多选;从'lodash'导入__;导出默认{name: '恢复更新',道具:['简历'],成分: {多选},数据:() =>({形式: {姓名: '',等级: '',薪水: '',经验: '',教育: [],就业:[]},提交:{形式:假,摧毁:假的,恢复:假},错误:[]}),方法: {更新(e){this.submitted.form = true;axios.put(e.target.action, this.form).then(response => {this.resume = response.data.datathis.submitted.form = false;}).catch(错误=>{如果(错误.响应){this.errors = error.response.data.errors;}this.submitted.form = false;});},破坏() {this.submitted.destroy = true;axios.delete(this.resume.routes.destroy).then(response => {this.resume = response.data.data;this.submitted.destroy = false;}).catch(错误=>{this.submitted.destroy = false;})},恢复() {this.submitted.restore = true;axios.post(this.resume.routes.restore).then(response => {this.resume = response.data.data;this.submitted.restore = false;}).catch(错误=>{this.submitted.restore = false;})},重启() {for (Object.getOwnPropertyNames(this.form)的const prop){删除 this.form[prop];}}},手表: {简历:函数(){this.form = this.resume;},},创建(){this.form = __.cloneDeep(this.resume);}}
当我提交表单并更新 this.resume
时,我得到以下信息:
[Vue 警告]:避免直接改变 prop,因为它的值将是每当父组件重新渲染时被覆盖.相反,使用一个基于道具值的数据或计算属性.道具变异:恢复"
我曾尝试将计算添加到我的文件中,但这似乎不起作用:
计算:{简历:函数(){返回 this.resume}}
那么,我该如何更新道具?
一个解决方案:
模拟v-model
As Vue 指南说:
<块引用>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 = falseVue.component('容器', {模板:`<p><button @click="changeData()">{{value}}</button></p></div>`,数据() {返回 {内部值:''}},道具:['价值'],挂载:函数(){this.internalValue = this.value},手表: {值:函数(新值){this.internalValue = newVal}},方法: {更改数据:函数(){this.internalValue + = '@'this.$emit('input', this.internalValue)}}})新的 Vue({el: '#app',数据 () {返回 {项目:['a', 'b', 'c']}}})<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script><div id="应用程序"><div><p>{{items}}<container v-for="(item, index) in items" :key="index" v-model="items[index]"></容器>
或使用其他道具名称代替值(下面的演示使用道具名称=item):
您也可以使用其他事件名称代替事件名称=输入.
其他步骤类似,但你必须在事件上 $on 然后像下面的演示一样实现你自己的处理程序.
Vue.config.productionTip = falseVue.component('容器', {模板:`<p><button @click="changeData()">{{item}}</button></p></div>`,数据() {返回 {内部值:''}},道具:['物品'],挂载:函数(){this.internalValue = this.item},手表: {项目:功能(新值){this.internalValue = newVal}},方法: {更改数据:函数(){this.internalValue + = '@'this.$emit('input', this.internalValue)this.$emit('test-input', this.internalValue)}}})新的 Vue({el: '#app',数据 () {返回 {项目:['a', 'b', 'c']}},方法: {同步更改:功能(目标,索引,新数据){this.$set(target, index, newData)}}})<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script><div id="应用程序"><div>事件名称=输入<p>{{items}}</p><container v-for="(item, index) in items" :key="index" :item="item" @input="syncChanged(items, index,$event)"></容器>
<小时>事件名称=测试输入<container v-for="(item, index) in items" :key="index" :item="item" @test-input="syncChanged(items, index,$event)"></容器>
So I have a simple template like so:
<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>
Now, inside the resume-update
component I am trying to update the prop on the inside so on the outside it doesn't get overwritten, my code is like so;
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);
}
}
When I submit the form and update the this.resume
I get the following:
[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "resume"
I have tried adding computed to my file, but that didn't seem to work:
computed: {
resume: function() {
return this.resume
}
}
So, how can I go about updating the prop?
One solution:
simulate v-model
As Vue Guide said:
v-model is essentially syntax sugar for updating data on user input events, plus special care for some edge cases.
The syntax sugar will be like:
the directive=v-model
will bind value, then listen input
event to make change like v-bind:value="val" v-on:input="val = $event.target.value"
So the steps:
create one prop = value which you'd like to sync to parent component
inside the child component, create one data porperty=internalValue, then uses Watcher to sync latest
prop=value
todata property=intervalValue
if
intervalValue
change, emit one input event to notice parent component
Below is one simple demo:
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>
or use other prop name instead of value (below demo use prop name=item):
Also you can use other event name instead of event name=input.
other steps are similar, but you have to $on the event then implement you own handler like below demo.
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>
这篇关于更新子组件内的道具,以便它也在父容器上更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!