vue的响应式原理
:网上看到一个关于vue的面试视频,里面讲到了一些关于vue的面试问题,包括视频主在其中的回答,感觉很有意思,其中多次提到了vue的响应式问题,心血来潮之下随便写点东西。
什么是响应式?
数据响应式就是数据变化时可以被检测并且对这种变化做出响应的机制。在vue中表现为数据的双向绑定,一般多使用为v-model,相信大家基本都用过。
vue的响应式就是通过底层的Object.defineProperty()方法对数据进行劫持,检测数据变化,调用dep的notify方法更新,然后结合发布订阅者模式实现的一种机制。
它所依赖的Object.defineProperty()是js中的一个在对象上定义新属性和修改属性的方法。使用这个方法需要三个参数:obj定义属性的当前对象、prop当前需要定义的属性名、desc一个描述符对象( 精准控制对象属性\初始值是false:
configurable 控制是否可以被删除、
enumerable 控制是否可以枚举、
writale 控制是否可以被修改、
value 属性数值)
(注:使用getter和setter方法则不可以使用writale和value属性,否则报错。获取值或者设置值的时候,控制是否可以修改的属性功能和此时功能冲突,应该很好理解。)
vue中非data定义的数据如何变成响应式?
因为vue是基于js之上实现的,所以它本身有无法检测属性添加和删除的功能。
只有在数据位于data()中,经过vue初始化实例执行getter/setter的转化才能够变成响应式的,每一个vue实例都会有一个监听者watcher检测属性变化,它会在组件渲染时把使用过的数据getter收集为依赖,当setter触发时watcher被唤醒然后重新渲染关联组件。 这样data数据发生变化,变化结果也会渲染到页面上。
可以理解为data()中的数据是和页面是同一级别的,其他数据是在页面下一层的,级别低一些,所以页面刷新数据不更新。
有data中的响应式数据那就有非响应式数据,有时候面试就会完响应式后再问:如何把非响应式的数据变成响应式的,这个在项目中也是用到比较多的一个情况。一些数据不方面写在data中,但是又需要去检测它的数据变化,从而更改页面上的渲染效果,此处有几个方法:
- 初始化数据: 就是将数据放在data中,前面也提到了数据放在data中经过vue初始化实例执行的getter/setter转化变成响应式的,然后触发监听者重新渲染组件。
data() {
return {
list: {
id:1,
text: 'number1'
}
}
}
- Vue.set()方法实现
vue原生自带set方法实现
Vue.set(this.list,"name","hahhahah")
- 使用this.$set 给响应式数据添加数据,这里添加的数据就是具有响应式的。
//和前面的例子联立,list里面的数据是响应式的,此时是利用$set将name注入到list里,所以name也是响应式的。
data() {
return {
list: {
id:1,
text: 'number1'
}
}
}
this.set(this.list,'name','hahhaha')
实质是这样的===>
data() {
return {
list: {
id:1,
text: 'number1',
name: 'hahhaha'
}
}
}
- 使用this.$foreUpdate()强制更新
this.list.name = 'hahahah'
this.$foreUpdate()
- Vue不允许在初始化实例之后添加属性,同时也不允许在初始化实例之后,删除属性,所以要想删除已经在data中定义好的对象中存在的属性,可以使用:
this.$delete(this.list,"name")