更新子组件内的道具,以便它也在父容器上更新 [英] Updating a prop inside a child component so it updates on the parent container too

查看:16
本文介绍了更新子组件内的道具,以便它也在父容器上更新的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我有一个像这样的简单模板:

<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"

所以步骤:

  1. 创建一个 prop = value,您希望将其同步到父组件

  2. 在子组件内部,创建一个数据属性=internalValue,然后使用Watcher将最新的prop=value同步到data property=intervalValue

  3. 如果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-updatecomponent 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:

  1. create one prop = value which you'd like to sync to parent component

  2. inside the child component, create one data porperty=internalValue, then uses Watcher to sync latest prop=value to data property=intervalValue

  3. 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屋!

查看全文
相关文章
前端开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆