双向数据绑定分为两个部分:
- 数据更新 ——-> 通知视图更新
- 用户操作改变视图数据 ————> 通知数据更新
主要由以下几个部分组成:
- Observer: 用于进行数据劫持,同时通过get / set钩子闭包来调用Dep进行依赖收集
- Dep:用于收集响应式数据中每一项(对象的属性)的依赖,也就是相应的watcher
- Watcher: 用于订阅响应式数据,原理是在初始化时通过去访问一次响应式数据触发其get钩子,从而订阅某数据,并且还用于指定数据变更后的回调函数。
- Compiler: 编译模板,将模板的花括号中的变量,指令渲染成对应数据,并且给每项数据新建一个watcher,绑定回调函数用于更新DOM
Observer
function Observer(data, vm) {
observe(data)
function observe(data) {
for (let key in data) {
let _value = data[key]
let dep = new Dep()
if (_value && typeof value === 'object') observe(_value)
Object.defineProperty(data, key, {
configurable: true,
enumerable: true,
get: function reactiveGetter() {
if (Dep.target) dep.addSub(Dep.target)
console.log('访问');
return _value
},
set: function reactiveSetter(newValue) {
if (_value === newValue) return
_value = newValue
if (newValue && typeof newValue === 'object') observe(newValue)
console.log('修改');
dep.notifyAll()
return _value
}
})
}
}
}
Dep
function Dep() {
this.subscribers = []
this.addSub = function (sub) {
if (this.subscribers.includes(sub)) return
this.subscribers.push(sub)
}
this.notifyAll = function () {
this.subscribers.forEach(sub => {
sub.update()
})
}
}
watcher
function Watcher(target, cb, vm) {
this.update = function () {
cb()
}
this.runWatch = function () {
Dep.target = this
this.getTargetValue(target, vm)
Dep.target = null
}
this.getTargetValue = function (target, vm) {
let value = vm.$data
target.split('.').forEach(key => value = value[key])
return value
}
this.runWatch()
}
Compiler
function Compiler(el, vm) {
console.log(vm);
this.$el = el
Array.from(this.$el.children).forEach(child => {
console.dir(child)
if (child.nodeType === 1) {
let reg = /\{\{(.*)\}\}/
let text = child.textContent.trim()
if (text && reg.test(text)) {
let key = RegExp.$1.trim()
child.innerText = vm.$data[key]
const watcher = new Watcher(key, () => {
child.innerText = watcher.getTargetValue(key, vm)
}, vm)
}
}
})
}