https://www.jianshu.com/p/2682b5a26869
定义:vue中双向绑定就是指v-model指令,可以绑定一个响应式数据到视图,同时视图中变化能同步改变该值。
通过Object.defineProperty( )
对属性设置一个set
函数,当数据改变了就会来触发这个函数,所以我们只要将一些需要更新的方法放在这里面就可以实现data更新view了。
vue数据双向绑定是通过数据劫持结合发布者-订阅者模式的方式来实现的。
我们已经知道实现数据的双向绑定,首先要对数据进行劫持监听,所以我们需要设置一个监听器Observer,用来监听所有属性。
如果属性发上变化了,就需要告诉订阅者Watcher看是否需要更新。
因为订阅者是有很多个,所以我们需要有一个消息订阅器Dep来专门收集这些订阅者,然后在监听器Observer和订阅者Watcher之间进行统一管理的。
接着,我们还需要有一个指令解析器Compile,对每个节点元素进行扫描和解析,将相关指令(如v-model,v-on)对应初始化成一个订阅者Watcher,并替换模板数据或者绑定相应的函数,此时当订阅者Watcher接收到相应属性的变化,就会执行对应的更新函数,从而更新视图。
因此接下去我们执行以下3个步骤,实现数据的双向绑定:
- 实现一个监听器Observer,用来劫持并监听所有属性,如果有变动的,就通知订阅者。
- 实现一个订阅者Watcher,每一个Watcher都绑定一个更新函数,watcher可以收到属性的变化通知并执行相应的函数,从而更新视图。
- 实现一个解析器Compile,可以扫描和解析每个节点的相关指令(v-model,v-on等指令),如果节点存在v-model,v-on等指令,则解析器Compile初始化这类节点的模板数据,使之可以显示在视图上,然后初始化相应的订阅者(Watcher)。
通过以上问题 - 我们引出 Vue监测数据的原理_对象:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript" src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.1/vue.js"></script>
</head>
<body>
<div id="v-school">
学校名称:{{ name }} <br/>
学校地址:{{ address }}
</div>
<script type="text/javascript">
let vm = new Vue({
el: '#v-school',
data: {
name: '北京大学',
address: '北京'
}
})
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script type="text/javascript">
let data = {
name: '尚硅谷',
address: '北京',
}
// 创建一个监视的实例对象,用于监视data中属性的变化
const obs = new Observer(data)
console.log(obs)
// 准备一个vm实例对象
let vm = {}
vm._data = data = obs
function Observer(obj) {
// 汇总对象中所有的属性
const keys = Object.keys(obj)
// 遍历
keys.forEach((k) => {
Object.defineProperty(this, k, {
get() {
return obj[k]
},
set(val) {
console.log('${k}被改了,我要去解析模板,生成虚拟DOM...我要开始忙了')
obj[k] = val
}
})
})
}
</script>
</body>
</html>
本次书写的代码为简化版,Vue更完善的点有:
如果要修改_data中的name,完整写法为 vm._data.name = ‘atguigu’ ,还可以直接简写为 vm.name = ‘atguigu’,因为Vue做了数据代理。
当对象中还有对象时,Vue也能做到有为其服务的getter和setter。Vue里面写了递归,有多少层就能写到多少层,直到那个东西不再是对象为止,对象在数组中也是如此。
Vue监测数据的原理,就是靠setter。
只要修改数据,Vue就会重新解析模板,生成虚拟DOM。
https://blog.csdn.net/zs18753479279/article/details/128553178