开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第20天
Vue的响应式原理简单介绍
使用Vue开发的项目能实现在数据发生改变时,界面紧跟着进行更新,这并不是js的原生特性,而是Vue底层替我们实现的。
什么是响应式
<div id="app">
{{message}}
</div>
<script>
const app = new Vue({
el:`#app`,
data:{
message: `111`
}
})
</script>
这样在我们的页面中就会显示出111
但如果我们在控制台改变message内容:
app.message=222
页面中的内容也会随之立即自动更改
我们接下来就看看,我们是怎么实现这种响应式改变的
实现响应的基本原理
要实现响应式,我们能想到的大致思路:
- 有一个监听message的监听器,看它什么时候发生了改变
- 记录哪里调用了message
- 当数据改变时,通知调用message的地方一同改变
前两个问题:如何监听改变和监听调用?
那它是如何进行监听的呢?
我们知道,创建Vue时传入的参数都是键值对形式的对象,传入后Vue底层就可以通过遍历来获取其中的每个元素:
Object.key(obj).forEach(key => {
let value = obj[key]
})
当它取到了每个键值对,就可以单独为他们定义set、get方法:
Object.key(obj).forEach(key => {
let value = obj[key]
Object.defineProperty(obj, key, {
set(newValue) {
value = newValue;
},
get(){
return value;
}
})
})
当我们通过obj.key改变值时,底层就会调用其obj[key].set方法来传入新值,那么我们就能利用set方法来进行监听值的改变
同样的,当我们通过obj.key来获取值时,底层就会调用其obj[key].get方法来获取值,那么我们就能利用get方法来监听值的获取
我们通过get和set就能知道值的改变和使用值的位置,接下来就需要将其关联起来👇
第三个问题:将值的改变和调用点关联起来——发布者订阅者
在掘金中,我关注(订阅)一个用户,该用户发帖时就会提醒到我 在Vue中,值的调用点关注(订阅)了对应的值,当值发生改变时就会提醒到调用点
那么它是如何订阅的呢?
我们定义一个Watcher类来创建订阅者(相当于关注别人的用户):
class Watcher{
constructor(name){
this.name = name;
}
}
我们定义一个Dep(dependency)类来记录订阅者,创建订阅关系(相当于被关注用户,即发布者):
class Dep{
constructor(){
this.subs = [];//记录订阅者的列表
}
addSub(watcher){
this.subs.push(watcher);//将新创建的订阅者加入到订阅者列表中
}
notify(){
this.subs.forEach(item => {
item.update();//调用每一个订阅者的update方法进行更新
})
}
}
接下来我们就可以实现订阅及更新通知了:
//在get中创建watcher类实例,并将其加入到对应属性的订阅者列表中
get(){
const w1 = new Watcher("第一个订阅点");
dep.addSub(w1);
return value;
}
//在set中调用dep的notify方法,完成所有订阅者的更新
set(newValue){
value = newValue;
dep.notify();
}