vue响应式原理
在实现整个Vue响应式代码之前,我们先来了解几个概念。
第一个:数据驱动
数据驱动是Vue最独特的特性之一
开发过程中仅仅需要关注数据本身,不需要关心数据是如何渲染到视图中的。主流的MVVM框架都已经实现了数据响应式与双向绑定,所以可以将数据绑定到DOM上。
数据驱动的内容
数据响应式:当我们修改数据时,视图会进行更新
双向绑定:数据改变,视图改变,视图改变,数据也随之改变( 通过这句话,我们可以看到在双向绑定中是包含了数据响应式的内容)
第二个:响应式的核心原理
关于Vue2.x的响应式原理在官方文档中也有介绍。cn.vuejs.org/v2/guide/re…
在该文档中,我们注意如下一段内容: 当你把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有的 property,并使用 Object.defineProperty 把这些 property 全部转为 getter/setter。Object.defineProperty 是 ES5 中一个无法降级(shim) 的特性,这也就是 Vue 不支持 IE8 以及更低版本浏览器的原因。
通过以上的文字,我们可以看到,在Vue2.x中响应式的实现是通过Object.defineProperty来完成的
Object.defineProperty()方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象
下面我们来看一下Object.defineProperty基本使用,修改data对象中的msg属性的值,实现视图的更新.(这也就是我们所说的响应式),如下:
在上面的代码中,我们是将一个对象中的属性转换成了getter/setter的形式,那么这里我们还有一个问题: 如果有一个对象中多个属性需要转换getter/setter,那么应该如何处理?
答:我们可以通过循环遍历的方式,将对象中的多个属性转换成getter/setter 如下:
Vue2响应式有一个缺点,需要通过循环递归遍历对象,性能不高。
Vue3响应式原理
Vue3的响应式原理是通过Proxy来完成的。
Proxy直接监听对象,而非属性,所以将多个属性转换成getter/setter的时候,不需要使用循环。
Proxy是ES6课程中新增的,IE不支持
第三个:发布订阅模式和观察者模式
发布订阅模式
发布订阅模式:订阅者,发布者,信号中心
我们假定,存在一个“信号中心”,某个任务执行完成,就向信号中心"发布"(publish)一个信号,其它任务可以向信号中心“订阅”(subscribe)这个信号,从而知道什么时候自己可以开始执行。这就叫做"发布/订阅模式"(publish-subscribe pattern)
Vue 的自定义事件就是基于发布订阅模式来实现的
下面通过Vue中兄弟组件通信过程,来理解发布订阅模式,如下:
App组件
</div>
<script>
let eventBus = new Vue()
let Aa = {
template: `<div class="wrap">A组件:<button @click="sendMsg">发布</button></div>`,
data() {
return {
Amsg: '我是来自A组建的信息',
}
},
methods: {
sendMsg() {
eventBus.$emit('eat', this.Amsg)
eventBus.$emit('drink', this.Amsg)
}
}
}
let Bb = {
template: `<div><h3>B组件:{{Bmsg}}</h3></div>`,
created() {
eventBus.$on('eat', (txt) => {
console.log("start eat...", txt);
})
eventBus.$on('drink', (txt) => {
console.log("start drink...", txt);
})
},
data() {
return {
Bmsg: '我是B组件',
}
},
methods: {
sendMsg() {
}
}
}
let vm = new Vue({
el: "#app",
components: {
Aa,
Bb,
}
})
</script>
当一个事件发生了,做什么?只能做一件吗?
答:一个事件发生了,可以做多件事,如下:
原生JS模拟实现自定义事件,如下:
Vue的响应式机制使用了观察者模式,所以我们首先要先了解一下观察者模式
观察者(订阅者) ---Watcher
update(): 当事件发生时,具体要做的事情。
目标(发布者) --Dep
subs 数组:存储所有的观察者
addSub() 添加观察者,将其保存到subs数组中
notify(): 当事件发生后,调用所有观察者的update() 方法。
下面我们看一下观察者模式与发布订阅模式的区别。
观察者模式:被观察者需要记录所有观察者
发布订阅模式:发布者和订阅者之间没有任何关系,彼此不知道对象的存在