Vue2.X 是如何利用 Object.defineProperty() 实现数据绑定的
上一篇文章写到了 Object.defineProperty 的应用,这篇文章说一下 Vue 是如何利用这个办法实现数据绑定的。
首先把 Vue 中的外围办法 defineReactive 做一些简化
function defineReactive (obj, key, val, cb) {var dep = new Dep();
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: ()=>{
/*.... 依赖收集等....*/
dep.depend()
return val
},
set:newVal=> {
val = newVal;
/* 触发回调 */
dep.notify()}
})
}
Vue 通过 defineReactive 办法实现对须要察看的对象的每个属性进行监控。
dep 对象就相当于一个调度核心的作用,如果有数据用到这个属性,它就会主动收集该属性到调度核心,如果某属性产生了扭转,那就会告诉调度核心来更新视图。
再看看 dep 办法和它的性能。绝对比较简单:1、存储订阅者 2、增加订阅者
function Dep () {
// 所有的 watcher 放进这里对立治理
this.subs = []}
Dep.target = null;
// 告诉视图更新 dom 的 notify 的办法
Dep.prototype.notify = function () {
// this.subs 存储 watcher
this.subs.forEach(sub => {
// sub 是某个 Watcher 具体调用某个 Watcher 的 update 办法
sub.update()})
}
// 增加订阅者的办法
Dep.prototype.addSub = function (sub) {this.subs.push(sub)
}
订阅器次要也是了两个办法;1、触发一下属性的获取,顺便把本人加到调度核心去 2、update 更新视图
// 具体的订阅器 Watcher
// 传入一个 vue 的示例,监听的属性,以及解决的回调函数
function Watcher (vm,prop,callback) {
this.vm = vm;
this.$prop = prop;
this.value = this.get();
this.callback = callback;
}
// 增加 watcher 取得属性的 get 办法,当有属性拜访 / 设置 的时候,就产生订阅者 将这个订阅者放进调度核心
Watcher.prototype.get = function () {
Dep.target = this;
// 取得属性值
const value = this.vm.$data[this.$prop];
return value
}
// 增加 watcher 的更新视图的办法
Watcher.prototype.update = function () {
// 当属性值有变动的时候,执行办法,更新试图
const value = this.vm.$data[this.$prop];
this.callback(this.value)
}
于是乎
当外界读取数据时会调用 watcher,会触发 getter 把 watcher 增加到 Dep 依赖中。(也就是编译过程收集依赖)
当数据产生了变动,会触发 setter,从而想 Dep 中的依赖(watcher)发送告诉。(交互过程,调度核心去告诉订阅器放松更新)。
Watcher 接管到告诉后,会向外界发送告诉,变动告诉到外界可能触发试图更新,也有可能触发用户的某个回调函数等。(订阅器批改对应的值,页面参数随之相应,实现响应)
当然,这才只是单向绑定,双向绑定就是说视图更改数据,这个就比较简单,在编译过程中将标签绑定 input 办法,批改对应的数据即可。
有来有回,实现了双向绑定。