vue响应式原理解析
1、什么是响应式
当修改data中的某一属性值时,调用该属性的界面视图也随着发生改变!
2、灵魂拷问
2.1 vue内部是如何监听数据的改变
答:使用Object.defineProperty监听对象属性的改变
2.2 当数据发生改变,vue是如何知道要通知哪些页面的?
答:使用发布者订阅者模式
3、代码解析
- 定义一个data对象,并获取它所有的属性与属性值
<script>
const data = {
message: "哈哈哈",
name: "lala"
}
// 获取data对象的所有属性与属性值
Object.keys(data).forEach(key=> {
let value = data[key]
})
</script>
- 使用Object.defineProperty()方法,侦测数据的变化(劫持用户对对象属性的取值和赋值)
<script>
const data = {
message: "哈哈哈",
name: "lala"
}
// 获取data对象的所有属性与属性值
Object.keys(data).forEach(key=> {
// 根据属性获取对应的属性值
let value = data[key];
Object.defineProperty(data, key, {
// 监听任意属性的改变
set(newValue) {
console.log('监听' + key+ '的改变');
value = newValue
},
// 获取任意属性的对应值
get() {
console.log('获取' + key+ '对应的值');
return value;
}
})
})
</script>
-
监听到某一属性(如:message)的改变后要如何?
答:告诉调用message的所有界面,数据发生改变了!
问:那又如何知道哪些界面调用message了呢?
答:根据解析html代码呀,看看那些页面在调用message。
路人甲:说白了,就是让界面订阅数据,一但某一数据发生改变,就要通知调用这一数据的界面,让他们更新数据! -
发布者订阅者模式
- 发布者
<script>
/*
* dependence:依赖 ===== 简写dep
* subscribe:订阅者 ===== 简写subs
*/
class Dep {
constructor() {
this.subs = [] // 该数组存储所有订阅者(对某一属性有依赖的东西)
}
// 添加订阅者
addSub(sub) {
this.subs.push(sub)
}
// 通知所有订阅者更新视图
notify() {
// 获取所有订阅者,并让每一个订阅者更新数据
this.subs.forEach( item => {
item.updated()
})
}
}
</script>
用 addSub 方法可以在目前的 Dep 对象中增加一个 sub 的订阅操作;
用 notify 方法通知目前 Dep 对象的 subs 中的所有 sub 对象触发更新操作。
所以当需要添加订阅者的时候调用 addSub,当需要派发更新的时候调用 notify。
<script>
let dep = new Dep()
dep.addSub()
dep.notify()
</script>
- 订阅者
<script>
class watcher {
constructor(name) {
this.name = name
}
// 更新数据
updated() {
console.log(this.name + '发生改变!!!');
}
}
</script>
每产生一个订阅者,将他添加进subs 中,并在数据发生变化时通知更改数据!
<script>
let w1 = new watcher('界面a')
dep.addSub(w1)
dep.notify()
</script>