双向数据绑定分为两个部分:
- 数据更新 ——-> 通知视图更新
- 用户操作改变视图数据 ————> 通知数据更新
主要由以下几个部分组成:
- 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 = newValueif (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)) returnthis.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 = thisthis.getTargetValue(target, vm)Dep.target = null}this.getTargetValue = function (target, vm) {let value = vm.$datatarget.split('.').forEach(key => value = value[key])return value}this.runWatch()}
Compiler
function Compiler(el, vm) {console.log(vm);this.$el = elArray.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)}}})}
