Vue data直接添加新的属性没有响应式解决方法

1,535 阅读1分钟

一、直接添加属性产生的现象

const app = new Vue({
    el:"#app",
    data:()=>{
       	item:{
            oldProperty:"旧属性"
        }
    },
    methods:{
        addProperty(){
            this.items.newProperty = "新属性"  // 为items添加新属性
            console.log(this.items)  // 输出带有newProperty的items
        }
    }
})

代码解析:当执行 addProperty 为 data 添加新属性时,data 确实更新了,但是没有响应式,页面并没有更新,众所周知 vue2 是用过 Object.defineProperty 实现数据响应式的,当我们调用 oldProperty 或者修改 oldProperty 的时候都能够触发他的 setter 与 getter 方法,是因为oldProperty 在初始化的时候就已经被 defineProperty 重新定义了,而 newProperty 是新添加的属性,并没有被 defineProperty 重新定义

二、解决方法

2-1 Vue.set()

  • 通过 Vue.set 向响应式对象中添加一个新的属性 ,并确保这个新属性同样是响应式的,且触发视图更新,无需在再调用 defineReactive 方法,实现新增属性的响应式

  • Vue.set( target, key, value ) / this.$set( target, key, value )
    target:要更改的数据源(可以是对象或者数组)
    key:新增的属性名
    value :重新赋的值

<template>
    <p>{{item.oldProperty}}</p>
    <p>{{item.newProperty}}</p>
    <button @click="dynamicClick()">新增属性</button> 
</template>    
<script>
       data() {
            return {
                   items:{ oldProperty:"旧属性"}
            }
        },
        methods: {
            dynamicClick:function(){
                    this.$set(this.items,"newProperty","新属性")
            },
        }
</script>

2-2 Object.assign()

直接使用 Object.assign() 添加到对象的新属性不会触发更新,应该合并原对象和混入对象的属性后,再去给对象重新赋值,就会触发更新,本质上就是通过重新给对象赋值,来使视图更新

<template>
    <p>{{item.oldProperty}}</p>
    <p>{{item.newProperty}}</p>
    <button @click="dynamicClick()">新增属性</button> 
</template>    
<script>
       data() {
            return {
                   items:{ oldProperty:"旧属性"}
            }
        },
        methods: {
            dynamicClick:function(){
                   this.items = Object.assign({}, this.items, {newProperty: "新属性"})
            }
        }
</script>

2-3 forceUpdate

$forceUpdate 会迫使 Vue 实例重新渲染,也就是强制更新,不建议使用