- Vue
把 data 中的成员注入到 Vue 实例,而且把 data 中的成员转成 getter/setter
- Observer
可以或许对数据对象的所有属性举行监听,如有变动可拿到最新值并关照 Dep
- Compiler
分析每个元素中的指令/插值表达式,并更换成相应的数据
- Dep
添加观察者(watcher),当数据变革关照所有观察者
- Watcher
数据变革更新视图
Vue
功能:
- 负责吸取初始化的参数(选项)
- 负责把 data 中的属性注入到 Vue 实例,转换成 getter/setter
- 负责调用 observer 监听 data 中所有属性的变革
- 负责调用 compiler 分析指令/插值表达式
class Vue { constructor (options) { // 1. 通过属性生存选项的数据 this.$options = options || {} this.$data = options.data || {} this.$el = typeof options.el === 'string' ? document.querySelector(options.el) : options.el // 2. 把data中的成员转换成getter和setter,注入到vue实例中 this._proxyData(this.$data) // 3. 调用observer对象,监听数据的变革 new Observer(this.$data) // 4. 调用compiler对象,分析指令和差值表达式 new Compiler(this) } _proxyData (data) { // 遍历data中的所有属性 Object.keys(data).forEach(key => { // 把data的属性注入到vue实例中 Object.defineProperty(this, key, { enumerable: true, configurable: true, get () { return data[key] }, set (newValue) { if (newValue === data[key]) { return } data[key] = newValue } }) }) }}Observer
功能:
- 负责把 data 选项中的属性转换成相应式数据
- data 中的某个属性也是对象,把该属性转换成相应式数据
- 数据变革发送关照
class Observer { constructor (data) { this.walk(data) } walk (data) { // 1. 判断data是否是对象 if (!data || typeof data !== 'object') { return } // 2. 遍历data对象的所有属性 Object.keys(data).forEach(key => { this.defineReactive(data, key, data[key]) }) } defineReactive (obj, key, val) { let that = this // 负责网络依赖,并发送关照 let dep = new Dep() // 假如val是对象,把val内部的属性转换成相应式数据 this.walk(val) Object.defineProperty(obj, key, { enumerable: true, configurable: true, get () { // 网络依赖 Dep.target && dep.addSub(Dep.target) return val }, set (newValue) { if (newValue === val) { return } val = newValue that.walk(newValue) // 发送关照 dep.notify() } }) }}Compiler
功能:
- 负责编译模板,分析指令/插值表达式
- 负责页面的首次渲染
- 当数据变革后重新渲染视图
class Compiler { constructor (vm) { this.el = vm.$el this.vm = vm this.compile(this.el) } // 编译模板,处理处罚文本节点和元素节点 compile (el) { let childNodes = el.childNodes Array.from(childNodes).forEach(node => { // 处理处罚文本节点 if (this.isTextNode(node)) { this.compileText(node) } else if (this.isElementNode(node)) { // 处理处罚元素节点 this.compileElement(node) } // 判断node节点,是否有子节点,假如有子节点,要递归调用compile if (node.childNodes && node.childNodes.length) { this.compile(node) } }) } // 编译元素节点,处理处罚指令 compileElement (node) { // console.log(node.attributes) // 遍历所有的属性节点 Array.from(node.attributes).forEach(attr => { // 判断是否是指令 let attrName = attr.name if (this.isDirective(attrName)) { // v-text --> text attrName = attrName.substr(2) let key = attr.value this.update(node, key, attrName) } }) } update (node, key, attrName) { let updateFn = this[attrName + 'Updater'] updateFn && updateFn.call(this, node, this.vm[key], key) } // 处理处罚 v-text 指令 textUpdater (node, value, key) { node.textContent = value new Watcher(this.vm, key, (newValue) => { node.textContent = newValue }) } // v-model modelUpdater (node, value, key) { node.value = value new Watcher(this.vm, key, (newValue) => { node.value = newValue }) // 双向绑定 node.addEventListener('input', () => { this.vm[key] = node.value }) } // 处理处罚其他指令 ... // 编译文本节点,处理处罚差值表达式 compileText (node) { // console.dir(node) // {{ msg }} let reg = /\{\{(.+?)\}\}/ let value = node.textContent if (reg.test(value)) { let key = RegExp.$1.trim() node.textContent = value.replace(reg, this.vm[key]) // 创建watcher对象,当数据改变动新视图 new Watcher(this.vm, key, (newValue) => { node.textContent = newValue }) } } // 判断元素属性是否是指令 isDirective (attrName) { return attrName.startsWith('v-') } // 判断节点是否是文本节点 isTextNode (node) { return node.nodeType === 3 } // 判断节点是否是元素节点 isElementNode (node) { return node.nodeType === 1 }}Dep
功能:
- 网络依赖,添加观察者(watcher)
- 关照所有观察者
class Dep { constructor () { // 存储所有的观察者 this.subs = [] } // 添加观察者 addSub (sub) { if (sub && sub.update) { this.subs.push(sub) } } // 发送关照 notify () { this.subs.forEach(sub => { sub.update() }) }}Watcher
功能:
- 当数据变革触发依赖, dep 关照所有的 Watcher 实例更新视图
- 自身实例化的时间往 dep 对象中添加自己
class Watcher { constructor (vm, key, cb) { this.vm = vm // data中的属性名称 this.key = key // 回调函数负责更新视图 this.cb = cb // 把watcher对象记载到Dep类的静态属性target Dep.target = this // 触发get方法,在get方法中会调用addSub this.oldValue = vm[key] Dep.target = null } // 当数据发生变革的时间更新视图 update () { let newValue = this.vm[this.key] if (this.oldValue === newValue) { return } this.cb(newValue) }}总结
- Vue
记载传入的选项,设置 $data/$el
把 data 的成员注入到 Vue 实例
负责调用 Observer 实现数据相应式处理处罚(数据挟制)
负责调用 Compiler 编译指令/插值表达式等
- Observer
数据挟制
负责把 data 中的成员转换成 getter/setter
负责把多层属性转换成 getter/setter
假如给属性赋值为新对象,把新对象的成员设置为 getter/setter
添加 Dep 和 Watcher 的依赖关系
数据变革发送关照
- Compiler
负责编译模板,分析指令/插值表达式
负责页面的首次渲染过程
当数据变革后重新渲染
- Dep
网络依赖,添加订阅者(watcher)
关照所有订阅者
- Watcher
自身实例化的时间往dep对象中添加自己
当数据变革dep关照所有的 Watcher 实例更新视图
|