取消 vue 组件中的属性更新

Posted

技术标签:

【中文标题】取消 vue 组件中的属性更新【英文标题】:Cancel property update in vue component 【发布时间】:2020-06-12 12:48:19 【问题描述】:

我有一个 Vue 组件来更新用户数据

<template>
  <form>

     ... fields to update user property ...

    <button class="btn btn-primary" :disabled="!isDirty" @click.prevent="submit">Submit</button>
    <button class="btn btn-default" @click.prevent="cancel">Cancel</button>
  </form>
</template>

<script>
export default 
  props: ["user"],
  methods: 
    submit() 
      this.$emit("formIsSubmitted", true);
    ,
    cancel() 

      ????

    
  
;
</script>

当我提交时,父组件中的用户被更新,因为它是一个通过引用传递的对象。 单击取消按钮时,如何将用户属性“重置”为其原始值?

我尝试在 created() 事件中创建一个克隆对象,然后将用户重置为该对象,但随后出现以下错误:

避免直接改变 prop,因为每当父组件重新渲染时,该值将被覆盖。相反,使用基于道具值的数据或计算属性。正在变异的道具:“用户”

【问题讨论】:

【参考方案1】:

好的,根据@Estradiaz 的回答,我找到了解决方案。 在组件的mounted() 中,我循环遍历用户的所有属性以进行复制。 取消时,我将这些道具复制回用户对象。

export default 
  props: ["user"],
  data: () => (
    initUser: 
  ),
  mounted() 
    for (const p in this.user) 
      this.initUser[p] = this.user[p];
    
  ,
  methods: 
    submit() 
      this.isDirty = false;
      this.$emit("formIsSubmitted", true);
    ,
    cancel() 
      for (const p in this.user) 
        this.user[p] = this.initUser[p];
      
      this.$emit("formIsSubmitted", `false);
    
  
;

【讨论】:

【参考方案2】:

所以基本上你想防止改变传递的 props 引用。

一种方法是使用计算的 getter/setter:

...
props: ["user],
data()return 
  [propname + '_']: ""
.
computed: 
  [propname]: 
    get()
       return this[propname + '_'] || this.user[propname]
       // or call cancel in mounted and just 
       return this[propname + '_']
    ,
    set(value)
       this[propname + '_'] = value
    
  

...
cancel()
   this[propname] = this.user[propname]

ofc 可以循环假设这等于展平和复制:

created()
  this.cancel()

props: ["user"]
data()return flatcopy: 
cancel()
  Object.entries(this.user)
  .forEach(([key,value]) => this.$set(this.flatcopy, key, value)

或某种混合风格(未经测试,但我认为应该以这种方式工作):

function mixin(propname)
return 
...
mounted()
  if(this.cancel && typeof this.cancel == "function")
     const cancel = this.cancel.bind(this)
     this.cancel = ()=> 

         this[propname] = this.user[propname]
         cancel()
     
    else 
         this.$set(this, cancel, (()=>this[propname] = this.user[propname]))
   

props: ["user],
data()return 
  [propname + '_']: ""
.
computed: 
  [propname]: 
    get()
       return this[propname + '_'] || this.user[propname]
       // or call cancel in mounted and just 
       return this[propname + '_']
    ,
    set(value)
       this[propname + '_'] = value
    
  



usage: 

  mixins: [mixin('anyname')]

【讨论】:

有没有一种方法可以循环遍历用户对象的数据元素,这样我就不必手动为每个道具名称进行设置?【参考方案3】:

你可以这样做

<template>
  <form>

     ... fields to update user property ...

    <button class="btn btn-primary" :disabled="!isDirty" @click.prevent="submit">Submit</button>
    <button class="btn btn-default" @click.prevent="user=">Cancel</button>
  </form>
</template>

<script>
export default 
  mounted()
    this.user = this.userObj;
  ,
  data()
     return 
         user: ,
     
  ,
  props: ["userObj"],
  methods: 
    submit() 
      this.$emit("formIsSubmitted", this.user);
    ,
  
;
</script>

【讨论】:

这样,user 和 userObj 将是相同的;因此在表单中更新用户也会更新 userObj(= 父组件中的用户)。取消时:用户将重置为 ,但 userObj(因此从父级传递的属性)不会。我想确保父母没有更新。 我一直在我的项目中广泛使用它。但是,如果由于某种原因它对您不起作用,您始终可以在 mounted 方法中从您的 prop 显式创建一个新对象。一种方法是JSON.parse(JSON.stringify(this.userObj))mounted;【参考方案4】:

created 内部,我建议创建一个变量userForm,将其设置为组件引用的user。然后,当您提交时,您可以重置userForm,因为它不是道具。

【讨论】:

以上是关于取消 vue 组件中的属性更新的主要内容,如果未能解决你的问题,请参考以下文章

Vue 计算属性已更新,但组件未重新渲染

vue props原理

vue组件中的“:”“@”“.”属性

Vue 2 从嵌套组件更新数组中对象的属性

Vue 父亲组件更新子组件后子组件属性数据不改变

Vue 组件没有正确更新属性