更新子组件内部的道具,以便它也在父容器上更新

时间:2018-08-21 18:31:30

标签: vue.js vuejs2

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

 sqldf("SELECT BP_OR, N_orden_OR, Tipo_ordenOR, N_lineaOR, OLUSER, OLPID, 
      (select Fecha_aprobac from aprob_or 
                 order by Fecha_aprobac desc limit 1) AS LastOfFecha_aprobac, 
                 Estadp_sig, Estado_ultimo
              FROM aprob_or
              GROUP BY BP_OR, N_orden_OR, Tipo_ordenOR, N_lineaOR, OLUSER, OLPID, Estadp_sig, Estado_ultimo
                 (((OLPID)='X43008'))
                ")

现在,在private void Info_MouseHover(object sender, EventArgs e) { Control senderObject = sender as Control; string hoveredControl = senderObject.Tag.ToString(); // only instantiate a tooltip if the control's tag contains data if (hoveredControl != "") { ToolTip info = new ToolTip { AutomaticDelay = 500 }; string tooltipMessage = string.Empty; // add all conditionals here to modify message based on the tag // of the hovered control if (hoveredControl == "save button") { tooltipMessage = "This button will save stuff."; } info.SetToolTip(senderObject, tooltipMessage); } } 组件内部,我正在尝试更新内部的prop,因此在外部它不会被覆盖,我的代码就是这样;

<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时,我得到以下信息:

  

[Vue警告]:避免直接更改道具,因为该值将是   父组件重新渲染时覆盖。而是使用   数据或基于属性值的计算属性。道具被   变异:“恢复”

我尝试将计算文件添加到我的文件中,但这似乎不起作用:

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);
    }
}

那么,我该如何更新道具?

2 个答案:

答案 0 :(得分:3)

我通常使用vuex来管理将在多个组件中使用的变量,并且如错误所述,使用计算出的属性将它们加载到各个组件中。然后使用商店对象的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;
    }
}

答案 1 :(得分:3)

一种解决方案:

模拟v-model

Vue Guide said

  

v-model本质上是语法糖,用于更新用户输入上的数据   事件,以及对某些极端情况的特殊照顾。

语法糖如下:

指令= v-model将绑定值,然后监听input事件以进行类似v-bind:value="val" v-on:input="val = $event.target.value"

的更改

步骤如下:

  1. 创建一个要与父组件同步的prop =

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

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

或使用其他道具名称代替(在演示下面,使用道具名称= 项目):

您还可以使用其他事件名称代替事件名称= 输入

其他步骤相似,但是您必须在事件上实现$,然后实现自己的处理程序,如以下演示所示。

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>