一、原理
用vue2开发产品的大家可能都知道,因为vue的definePrototype(访问器属性)原因,初始时就在data里面的数据会受到监听,但是当我们给响应式的对象新增属性的时候,新增的属性并不会显示到页面中;同样对于响应式的数组,增加元素、修改数组长度时,数组的变化也不会展示在页面上。
<template> <div> <h2>{{ obj }}</h2> <h2>{{ arr }}</h2> </div> </template> <script> export default { data() { return { obj: { a: "Hello World!", }, arr: [1, 2, 3], }; }, mounted() { this.changeObj(); this.changeArr(); }, methods: { changeObj() { this.obj.b = "新增的属性b"; console.log(this.obj); }, changeArr() { this.arr[4] = 7; this.arr.length = 5; console.log(this.arr); }, }, }; </script>
通过上面的demo我们可以看出,页面加载后通过this.obj.b="..."时,页面并没有将属性b展示出来;但是通过console()我们却可以发现,明明obj上面存在属性b但是页面上却并没有展示出来,这是为什么呢?
上面也已经提到过,因为vue2的双向绑定原理问题,对象obj及其属性a在vue初始化时已处理成响应式的,即当我们改变对象obj的值或属性a的值时,会触发其在页面上的更新,但是当页面加载完成后,新增的属性b和c就不是响应式的,虽然通过打印this.obj可以看出对象obj上确实增加了属性b和c,但是由于b和c不是响应式的,所以新增的属性不会体现在页面上。
二、this.$set()解决
对上面我们遇到的问题,通常可以采用this.$set()来解决;
this.$set()怎么用呢?
在使用this.$set(target, key, value)
时,target为需要添加属性的对象,key是要添加的属性名,value为属性key对应的值。
<template> <div> <h2>{{ obj }}</h2> <h2>{{ arr }}</h2> </div> </template> <script> export default { data() { return { obj: { a: "Hello World!", }, arr: [1, 2, 3], }; }, mounted() { this.changeObj(); this.changeArr(); }, methods: { changeObj() { // this.obj.b = "新增的属性b"; this.$set(this.obj, "b", "新增的属性b"); console.log(this.obj); }, changeArr() { // this.arr[4] = 7; // this.arr.length = 5; this.$set(this.arr, "3", 7); console.log(this.arr); }, }, }; </script>
这时我们再来看页面已经发生了变化,当然数据更新页面没有更新的解决方法很多!