V008-vue中数据变化页面并不变化问题
由于我们vue2中的数据双向绑定时候经常遇到这种,数据变化了,视图没有变化的情况,这是为什么呢?怎么解决呢?
探索1
data() {
obj1:{}
}
btn1() {
this.obj1.name = '123'
},
btn2() {
this.obj1.name = '变了呀'
},
<div @click="btn1">按钮1</div>
<div @click="btn2">按钮2</div>
<div>{{obj1}}</div>
当点击按钮1和按钮2时候,页面上的obj1是一点没有变化的,也就是经典的那种数据变了,页面没有变。
但是,当我们给obj1一个初始属性name时候,在改变name,就会发现,页面还是同步的。
探索2
data() {
obj1:{
name:'我是初始值'
}
}
btn1() {
this.obj1.name = '123'
},
btn2() {
this.obj1.name = '变了呀'
},
<div @click="btn1">按钮1</div>
<div @click="btn2">按钮2</div>
<div>{{obj1}}</div>
我们继续探索
我们再加深一层
探索3
data() {
obj1:{
name:{
age:12
}
}
}
btn1() {
this.obj1.name.age = '123'
},
btn2() {
this.obj1.name.age = '变了呀'
},
<div @click="btn1">按钮1</div>
<div @click="btn2">按钮2</div>
<div>{{obj1}}</div>
发现这样也是变了的
所以我们可以得出结论
只有在data里初始化的数据才是响应的,Vue不能检测到对象属性的添加或删除,没有在data里声明的属性不是响应的。跟对象的层级多少也没有关系的
明白怎么造成的了,那咋解决呢?
比如这个改变了这个newArr的数据
newArr:[]
我们直接赋值
let arr = [{name:'前端架构师'}]
this.newArr[0].newList = arr
会发现数据变了,页面没有变
有几种方法来解决这个问题
#方法1. 用 Object.assign
this.newArr[0].newList = arr
this.newArr = Object.assign({},this.newArr)
用Object.assign 追加属性
this.newArr = Object.assign({}, this.newArr, {
age: 12,
grade: '100'
})
这个Object.assign并不是深拷贝,只复制了一层。。
eg1:
data() {
obj1:{}
}
btn2() {
this.obj1.page = 1
this.obj1 = Object.assign({},this.obj1)
console.log(this.obj1)
},
```js
这样就同步了
但我们在往深了一层呢?
这里就有一个面试题了
let obj = { a:1, b:{ x:1, y:1, } }
let obj1 = Object.assign({}, obj) obj.a= 2
console.log(obj.a) // 2 console.log(obj1.a) // 1 说明第一层拷贝没问题
obj.b.x = 2 console.log(obj.b.x) //2 console.log(obj1.b.x) //2
说明深层没有拷贝
#方法2. 用 this.$set
let arr = [{name:'前端架构师'}] this.$set(this.newArr[index],'newList',arr)
或 Vue.set(this.newArr[index],'newList',arr)
有同学说,姨?我怎么用this.$set改了也不管用呢
那是因为
data() { obj1:{
} }
btn2() { this.obj1.name = '小明' this.$set(this.obj1,name,'小明') }
你用this.$set之前你是不是还对相同的属性做了赋值操作,把this.obj1.name = '小明'这个去掉就生效了。
## 3.生成新数组的方法
数组数据变动,使用某些方法操作数组,变动数据时,有些方法无法被vue监测
> push(),pop(),shift(),unshift(),splice(),sort(),reverse()可被vue检测到
> filter(), concat(), slice()。这些不会改变原始数组,但总是返回一个新数组。当使用非变异方法时,可以用新数组替换旧数组。
vue不能检测以下变动的数组: 1、当你利用索引直接设置一个项时,vm.items[indexOfItem] = newValue 2、当你修改数组的长度时,例如: vm.items.length = newLength
比如你在监听不到变化的数组后面加个concat
arr 是那个变了数组
arr.concat([]);
## 4.this.$forceUpdate()
> vue多层循环,动态改变数据后渲染的很慢或者不渲染
可在动态改变数据的方法,第一行加上
this.$forceUpdate();
## 5. 异步更新队列 this.$nextTick()
数据第一次获取到了,也渲染了,但是第二次之后数据只有在再一次渲染页面的时候更新,并不能实时更新。
Vue 异步执行 DOM 更新。只要观察到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据改变。如果同一个 watcher 被多次触发,只会被推入到队列中一次。
data() { obj:'未更新' }
btn2() { this.obj = '已更新' console.log(this.$el.textContent) //未更新 this.$nextTick(() => { console.log(this.$el.textContent) //已更新 }) }
因为 $nextTick()返回一个 Promise 对象,所以上面写法可以优化一下
async btn2() { this.obj = '已更新' console.log(this.$el.textContent) //未更新
await this.$nextTick() console.log(this.$el.textContent) //已更新 }