likes
comments
collection
share

vue2的缺陷

作者站长头像
站长
· 阅读数 49

下班回家的途中,一个问题困扰我很久,在vue2中为什么不能给对象直接赋值? 若是使用其他的的api又觉得麻烦,于是就有了这篇博客!!!

数组的部分操作也没有响应式

  • push(),pop(),shift(),unshift(),splice(),sort(),reverse()

因为这7个api会修改原数组,换句话来说,只要不修改原数组的api都没有响应式.

一、直接添加属性的问题

我们从一个例子开始

定义一个p标签,通过v-for指令进行遍历

然后给botton标签绑定点击事件,我们预期点击按钮时,数据新增一个属性,界面也 新增一行

<p v-for="(value,key) in item" :key="key">
    {{ value }}
</p>
<button @click="addProperty">动态添加新属性</button>

实例化一个vue实例,定义data属性和methods方法


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

点击按钮,发现结果并不是我所想的,数据虽然更新了(console打印出了新属性),但页面并没有更新

二、原理分析

下面来分析一下

由于vue2是用过Object.defineProperty实现数据响应式

const obj = {}
Object.defineProperty(obj, 'foo', {
        get() {
            console.log(`get foo:${val}`);
            return val
        },
        set(newVal) {
            if (newVal !== val) {
                console.log(`set foo:${newVal}`);
                val = newVal
            }
        }
    })
}

当我们访问foo属性或者设置foo值的时候都能够触发setter与getter

obj.foo   
obj.foo = 'new'

但是我们为obj添加新属性的时候,却无法触发事件属性的拦截

obj.bar  = '新属性'

原因是一开始obj的foo属性被设成了响应式数据,而bar是后面新增的属性,并没有通过Object.defineProperty设置成响应式数据

三、解决方案

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

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

  • Vue.set()
  • Object.assign()
  • $forcecUpdated()

自我认为 三种方法中了解一个即可

Vue.set()

格式:

  fn2(){
      // 添加一个属性+有响应式
      // vue提供的API
      // $set(对象,属性名,属性值)
      this.$set(item, this.items.newProperty, '新属性')
    },

具体参考 cn.vuejs.org/v2/api/#Vue…