关于vue给对象新增属性页面不会动态更新的问题

关于vue给对象新增属性页面不会动态更新的问题,第1张

问题

不知道大家有没有遇到过这个问题,当我们给data里面声明的对象添加一个新属性,这个新属性是不会动态更新视图的。

看一个例子

<template>
  <div>
    {{obj}}<br>
	<button @click="addProperty">动态添加新属性</button>
  </div>
</template>

<script>
export default {
    data(){
        return {
            obj:{
                oldProperty:"旧值"
            }
        }
    },
    methods:{
        addProperty(){
            this.obj.newProperty = "新值" 
            console.log(this.obj)  
        }
    }

};
</script>
在浏览器中输出的是最新结果,但是页面视图并没有更新
原因

vue2使用Object.defineProperty实现数据响应式

组件初始化时,对data中的obj进行递归遍历,对obj的每一个属性进行劫持,添加set,get方法。我们后来新加的newProperty属性,并没有通过Object.defineProperty设置成响应式数据,所以修改后不会视图更新

解决

Vue 不允许在已经创建的实例上动态添加新的响应式属性

若想实现数据与视图同步更新,可采取下面三种解决方案:

1. Vue.set( target, key, value)

参数

target:要修改的对象或数组
key:属性或下标
value:新值

methods:{
    addProperty(){
        this.$set(this.obj, "newProperty", "新值");
        console.log(this.obj)  
    }
}

我们可以看到页面已经更新了:

2. Object.assign(target, ...sources)

参数

target:目标对象
souce:源对象(可多个)

直接使用Object.assign()添加到对象的新属性不会触发更新
应创建一个新的对象,合并原对象和混入对象的属性

methods:{
    addProperty(){
    	// this.obj = Object.assign(this.obj,{newProperty:'新值'}) 
    	// 以上写法不会更新,要生成一个新对象
        this.obj = Object.assign({},this.obj,{newProperty:'新值'})
        console.log(this.obj)  
    }
}

3. lodash

也可以使用lodash库的_assign()_merge()为对象添加响应式属性,触发视图更新
this.obj = _assign({},this.obj,{newProperty:'新值'})
this.obj = _merge({},this.obj,{newProperty:'新值'})

4. $forcecUpdated()
$forceUpdate迫使Vue 实例重新渲染(不建议使用)

methods:{
    addProperty(){
        this.obj.newProperty = "新值" 
        this.$forceUpdate();
        console.log(this.obj)  
    }
}

5. 对于数组

# 数组对象直接修改属性,可以触发视图更新
arr:[{name:'uu盘'},{name:'hhh'}]
this.arr[0].name = 'hhh'
this.arr.forEach(item=>{
    item.name = 'gungun'
})
# splice方法修改数组,可以触发视图更新
arr:[{name:'uu盘'},{name:'hhh'}]
this.arr.splice(0,1)
# 数组赋值为新数组,可以触发视图更新
arr:[{name:'uu盘'},{name:'hhh'}]
this.arr = this.arr.filter(item=>item.name.includes('h'))
# Vue提供了如下的数组的变异方法,可以触发视图更新
push()
pop()
shift()
unshift()
splice()  
sort()
reverse()
<template>
  <div>
    {{obj}}<br>
    {{arr}}
	<button @click="addProperty">动态添加新属性</button>
  </div>
</template>

<script>
export default {
    data(){
        return {
            obj:{
                oldProperty:"旧值"
            },
            arr:[{name:'uu盘'},{name:'hhh'}]
        }
    },
    methods:{
        addProperty(){
        	// this.arr = this.arr.filter(item=>item.name.includes('h'))
        	// this.arr.splice(0,1)
        	// this.arr[0].name = 'hhh'
            this.arr.forEach(item=>{
                item.name = 'gungun'
            })
            this.obj.newProperty = "新值"
            console.log(this.obj)  
        }
    }

};
</script>
当我们点击按钮之后,数据与视图同步更新

注意:在页面中我们要使用arr变量才能有效

总结 如果为对象添加少量的新属性,可以直接采用Vue.set()如果需要为新对象添加大量的新属性,则通过Object.assign()创建新对象如果你需要进行强制刷新时,可采取$forceUpdate() (不建议)

注意:vue3是用过proxy实现数据响应式的,直接动态添加新属性仍可以实现数据响应式

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/web/1323121.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-12
下一篇 2022-06-12

发表评论

登录后才能评论

评论列表(0条)

保存