vue2的双向绑定原理基于数据劫持来实现。核心方法为Object.defineProperty
但是在以下代码中我们发现vue2的双向绑定并不能监听到,因为这样的逻辑仅仅是对data下面的一层进行了劫持,而再往下的改变是监听不到的,所以就引出了两外一个东西:wacth
和vue.$set
由于其同样无法监听数组,所以数组的改变通过数组方法才会触发更新(如splice
)。
<template>
<view>
{{object}}
<br>
{{arr}}
</view>
</template>
<script>
export default {
name:'index',
data() {
return {
object:{}
};
},
methods:{
},
onShow() {
this.object.names = 5
this.object.age = 'kl'
setTimeout(()=>{
this.object.aa = 'kl'
},0)
}
}
</script>
而在vue3中使用了ES6的Proxy(代理)
代理和数据data绑定之后,任何操作都会经过代理实现,就没有了监听不到的情况。在vue3中,通常使用ref和reactive进行数据绑定,注意其获取数值方式的.value
方法而非直接获取。
function Dep() {
this.subs = []
}
Dep.prototype = {
addSub(sub) {
this.subs.push(sub)
},
notify() {
this.subs.forEach(sub=>sub.update())
}
}
双向绑定的原理总的来说是基于 `发布-订阅者`模式
其中核心组成部分:
监听器Observer: 即数据劫持
订阅者容器: 监听器监听到数据变动时,遍历订阅者容器发布消息
Compile:解析模板指令,将模板中的变量替换成数据,比如{{name}}
Watcher: 连接Observe和Compile的桥梁
Vue双向绑定原理是采用发布订阅者模式,在初始化时劫持数据的各个属性的setter/getter
,在数据变动时发布消息给订阅者,触发响应的监听回调。而每个组件都对应一个Watcher实例,它会在组件渲染的过程中把接触过的数据记录为依赖,当依赖的setter
出发时,会通知Watcher
,从而使组件重新渲染