Vue 数据更新页面视图未渲染 问题
想解决问题,先看官方api
点击查看 Vue 深入响应式原理
这个api
很详细的说明了 vue
的数据变化与视图更新的原理,推荐先阅读这篇信息,下面再分享一点自己在项目中实际踩过的一些坑。
总结一下API中的信息
1.一个最重要最基础的要实现响应式,你必须在初始化实例前声明所有根级响应式 property
,哪怕只是一个空值。
对于基础类型数据,只要是你初始化了,后面不管怎么更改数据,都会触发更新对应视图
2.对于对象,每次更改请 直接 更改 根级别的响应式 property
,或者 通过 Vue.set(object, propertyName, value)
的方法更改属性。
在我们平时开发中,最容易出现的就是使用对象时数据已更新,视图未更新。出现这种问题,主要就是更改根级别的响应式property
后 还增加了其他属性。比如:
export default {
data() {
treeData: [],
},
methods: {
// 假设这是一个获取 tree 数据接口,data就是tree 数据
getTree(this.params).then(({data}) => {
this.treeData = data // 这里就是更改了根级别响应式的 treeData 这个 property
this.format(data)
}),
// 这个树我们需要默认展开每个节点
format(data) {
data.forEach(item => {
// 这里就是新增了其他(expand)属性,如果后端返回的数据默认有expand 这个属性
// 这里的修改没什么问题,但是如果没有,就属于新增了属性
// 需要使用上面api 里提到的
// Vue.set(item, 'expand', true)
// 如果不使用Vue.set方法,上面的 this.treeData = data 放到 this.format(data) 下面,更改完后再更改 根级响应property
item.expand = true
item.children && this.format(item.children)
})
}
}
}
3.数组,常用方法都能触发响应,例如:push
,pop
,shift
,unshift
,splice
等等,直接通过下标更改和通过length
赋值更改数组长度不能响应。
如果是数组对象,使用循环方法forEach
,map
等循环时,在循环内部 直接通过item.property
更改数据,只要当前数组在根级响应式property
添加了,并且数组内的对象不是通过下标 赋值的 , 都能触发响应(包括更深层次的多维数组对象)。比如:
<template>
<div class="test-component">
<button v-for="(item, i) in arr" :key="i" @click="changeHandle(item)">{{item.number}}</button>
</div>
</template>
<script>
export default {
data() {
return{
arr: [{
number: 1
}],
}
},
created() {
this.arr.push({ number: 2})
this.arr[2] = { number: 4}
},
methods: { ,
changeHandle(item) {
item.number++
}
}
}
</script>
可以看到,通过默认初始化的数据能自增响应,通过push
插入的也能,但是通过下标赋值的就不能触发响应了。
只有在更改前两个数据时触发了响应函数,vue 去对比数据变化,发现第三个数据也变化了,因此第三个数据就在页面上显示出了最新值。
因此上面说的要初始化,只是为了让数据更新能触发响应。所以大家在使用vue时也经常遇到第三个数据点击不变化,触发其他更新响应时才变化。
4.一个不建议使用的方法
在上面知道了,即使数据变化无法触发更新响应,但是其他更新响应触发了也会检查当前数据变化。
如果实在找不到自己写得代码哪里出了问题,可以使用hack
方法,就是手动在无法响应的地方添加一个data-listen-update
之类的属性,在data 中初始化一个根级响应 property
,每次更改数据就 给这个property
重新赋值,使其触发更新视图检查。如果无效,可以用下面的方法更暴力一点。
exprot default {
data() {
return {
update: true, // update 放到要更新处 的 v-if=“update” 中
}
},
methods: {
change() {
// 这里是更改了数据的代码
this.update = false
this.$nextTick(() => { this.update = true })
}
}
}
这是一个很暴力的方法,不建议使用,实在解决不了再使用吧。
总结
触发更新响应其实就只需要注意几点事情,根级响应property
一定要添加,对象加属性、数组加数据 要使用 Vue.set
方法。
没了,就这么点,是不是很简单。
以上如有疏漏或错误,欢迎指正,谢谢