🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[TOC] ****** ## 4 [\core\observer\] 数据绑定目录 >注:本节机制见基础原理的数据绑定 ### 4-1 目录文件 ~~~ \core\observer\ index.js ;数据监控器observer dep.js ;消息订阅器 watcher.js ;消息订阅者 batcher.js ;刷新 array.js ;数组监控 ~~~ ### 4-2 index.js(数据监控器) >[info] import ~~~ ;(导入) 消息订阅器,数组监控器,基础工具 import Dep from './dep' import { arrayMethods } from './array' import { def, remove, isArray, isObject, isPlainObject, hasProto, hasOwn, isReserved } from '../util/index' ~~~ >[info] module ~~~ ;数据监控方法键名 const arrayKeys = Object.getOwnPropertyNames(arrayMethods) ;是否需要递归转换响应属性 export const observerState = { shouldConvert: true } ;创建数据监视器 export function Observer (value) { this.value = value this.dep = new Dep() def(value, '__ob__', this) ;数组类型值监视 if (isArray(value)) { const augment = hasProto ? protoAugment : copyAugment augment(value, arrayMethods, arrayKeys) this.observeArray(value) } else { ;普通类型值监视 this.walk(value) } } ;普通数据遍历转换 Observer.prototype.walk = function (obj) { for (const key in obj) { this.convert(key, obj[key]) } } ;数组数据遍历转换 Observer.prototype.observeArray = function (items) { for (let i = 0, l = items.length; i < l; i++) { observe(items[i]) } } ;数据转换为响应属性 Observer.prototype.convert = function (key, val) { defineReactive(this.value, key, val) } ;添加数据监视器与vm关联 Observer.prototype.addVm = function (vm) { (this.vms || (this.vms = [])).push(vm) } ;注销数据监视器与vm关联 Observer.prototype.removeVm = function (vm) { remove(this.vms, vm) } ;数组类型值参数proto实现 function protoAugment (target, src) { /* eslint-disable no-proto */ target.__proto__ = src /* eslint-enable no-proto */ } ;数组类型值参数copy实现 function copyAugment (target, src, keys) { for (let i = 0, l = keys.length; i < l; i++) { const key = keys[i] def(target, key, src[key]) } } ;创建数据的监视器并关联vm export function observe (value, vm) { if (!isObject(value)) { return } let ob if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) { ob = value.__ob__ } else if ( observerState.shouldConvert && (isArray(value) || isPlainObject(value)) && Object.isExtensible(value) && !value._isVue ) { ob = new Observer(value) } if (ob && vm) { ob.addVm(vm) } return ob } ;创建对象的属性位响应,这里实现数据双向绑定 export function defineReactive (obj, key, val) { ;set操作消息订阅数组 const dep = new Dep() ;检查属性的描述信息 const property = Object.getOwnPropertyDescriptor(obj, key) if (property && property.configurable === false) { return } // cater for pre-defined getter/setters const getter = property && property.get const setter = property && property.set let childOb = observe(val) ;生成响应属性 Object.defineProperty(obj, key, { enumerable: true, configurable: true, get: function reactiveGetter () { ;获取值 const value = getter ? getter.call(obj) : val ;是否需要添加到消息订阅数组 if (Dep.target) { dep.depend() if (childOb) { childOb.dep.depend() } if (isArray(value)) { for (let e, i = 0, l = value.length; i < l; i++) { e = value[i] e && e.__ob__ && e.__ob__.dep.depend() } } } return value }, set: function reactiveSetter (newVal) { ;获取值,并比较新旧值 const value = getter ? getter.call(obj) : val if (newVal === value) { return } ;值不同进行修改 if (setter) { setter.call(obj, newVal) } else { val = newVal } ;创建位数据监视器 childOb = observe(newVal) ;广播到消息订阅数组中 dep.notify() } }) } ;对象属性修改快捷方式 export function set (obj, key, val) { ;数组类型值属性修改 if (isArray(obj)) { return obj.splice(key, 1, val) } ;普通对象属性值修改 if (hasOwn(obj, key)) { obj[key] = val return } ;Vue对象属性值修改obj._data if (obj._isVue) { set(obj._data, key, val) return } ;响应数据值__ob__修改 const ob = obj.__ob__ if (!ob) { obj[key] = val return } ob.convert(key, val) ob.dep.notify() ;vms相应修改 if (ob.vms) { let i = ob.vms.length while (i--) { const vm = ob.vms[i] proxy(vm, key) vm.$forceUpdate() } } ;返回修改后的值 return val } ;删除对象属性快捷方法 export function del (obj, key) { ;普通对象 if (!hasOwn(obj, key)) { return } delete obj[key] ;响应对象 const ob = obj.__ob__ if (!ob) { if (obj._isVue) { delete obj._data[key] obj.$forceUpdate() } return } ob.dep.notify() if (ob.vms) { let i = ob.vms.length while (i--) { const vm = ob.vms[i] unproxy(vm, key) vm.$forceUpdate() } } } ;$与_数据代理模拟生成vm._data export function proxy (vm, key) { if (!isReserved(key)) { Object.defineProperty(vm, key, { configurable: true, enumerable: true, get: function proxyGetter () { return vm._data[key] }, set: function proxySetter (val) { vm._data[key] = val } }) } } ;数据代理注销模拟 export function unproxy (vm, key) { if (!isReserved(key)) { delete vm[key] } } ~~~ >[info] export ~~~ ;(导出)数据监控器 export function Observer (value) {} ;(导出)数据监控注册到vm export function observe (value, vm) {} ;(导出)生成响应属性 export function defineReactive (obj, key, val) {} ;(导出)修改对象属性 export function set (obj, key, val) {} ;(导出)删除对象属性 export function del (obj, key) {} ;(导出)属性代理模拟 export function proxy (vm, key) {} ;(导出)属性代理注销模拟 export function unproxy (vm, key) {} ~~~ ![](https://box.kancloud.cn/2016-05-06_572bf787b395e.jpg) ### 4-3 dep.js(消息订阅器) >[info] import ~~~ ;(导入)删除数组项 import { remove } from '../util/index' ~~~ >[info] module ~~~ ;dep的id let uid = 0 ;Dep结构组织id和subs数组 export default function Dep () { this.id = uid++ this.subs = [] } ;消息订阅数组状态标志;用于绑定数据监视器 Dep.target = null ;消息订阅数组添加消息订阅者 Dep.prototype.addSub = function (sub) { this.subs.push(sub) } ;消息订阅数组删除消息订阅者 Dep.prototype.removeSub = function (sub) { remove(this.subs, sub) } ;消息订阅者添加到消息订阅数组 Dep.prototype.depend = function () { Dep.target.addDep(this) } ;广播消息订阅数组用于刷新 Dep.prototype.notify = function () { const subs = this.subs.slice() for (let i = 0, l = subs.length; i < l; i++) { subs[i].update() } } ~~~ >[info] export ~~~ ;(导出)消息订阅数组 export default function Dep () {} ~~~ ![](https://box.kancloud.cn/2016-05-06_572bf787b395e.jpg) ### 4-4 watcher.js(消息订阅者) >[info] import >[info] module >[info] export ![](https://box.kancloud.cn/2016-05-06_572bf787b395e.jpg) ### 4-5 batcher.js(刷新) >[info] import ~~~ ;(导入)消息订阅数组,刷新模块,基础工具 import Dep from './dep' import { pushWatcher } from './batcher' import { warn, remove, extend, isArray, isObject, parsePath, _Set as Set } from '../util/index' ~~~ >[info] module ~~~ ;uid,前一个Watcher let uid = 0 let prevTarget ;消息订阅者 export default function Watcher (vm, expOrFn, cb, options) { ;初始化参数 if (options) { extend(this, options) } ;待解析表达式 const isFn = typeof expOrFn === 'function' ;vm与vm._watchers this.vm = vm vm._watchers.push(this) ;解析表达式 this.expression = expOrFn this.cb = cb ;uid this.id = ++uid // uid for batching ;状态控制 this.active = true this.dirty = this.lazy // for lazy watchers ;Dep管理 this.deps = [] this.newDeps = [] this.depIds = new Set() this.newDepIds = new Set() ;表达式解析为getter if (isFn) { this.getter = expOrFn } else { this.getter = parsePath(expOrFn) if (!this.getter) { this.getter = function () {} process.env.NODE_ENV !== 'production' && warn( 'Failed watching path: ' + expOrFn + 'Watcher only accepts simple dot-delimited paths. ' + 'For full control, use a function instead.', vm ) } } ;值获取 this.value = this.lazy ? undefined : this.get() this.queued = this.shallow = false } ;Watcher.get():watcher值获取 Watcher.prototype.get = function () { ;get前回调 this.beforeGet() ;getter调用 const value = this.getter.call(this.vm, this.vm) ;递归调用 if (this.deep) { traverse(value) } ;get后回调 this.afterGet() ;返回获取的值 return value } ;get前依Dep保存 Watcher.prototype.beforeGet = function () { prevTarget = Dep.target Dep.target = this } ;Watcher.addDep()添加Watcher到Dep Watcher.prototype.addDep = function (dep) { const id = dep.id if (!this.newDepIds.has(id)) { this.newDepIds.add(id) this.newDeps.push(dep) if (!this.depIds.has(id)) { dep.addSub(this) } } } ;get后dep恢复 Watcher.prototype.afterGet = function () { Dep.target = prevTarget let i = this.deps.length while (i--) { const dep = this.deps[i] if (!this.newDepIds.has(dep.id)) { dep.removeSub(this) } } let tmp = this.depIds this.depIds = this.newDepIds this.newDepIds = tmp this.newDepIds.clear() tmp = this.deps this.deps = this.newDeps this.newDeps = tmp this.newDeps.length = 0 } ;Watcher.update():watcher刷新 Watcher.prototype.update = function (shallow) { if (this.lazy) { this.dirty = true } else if (this.sync) { this.run() } else { this.shallow = this.queued ? shallow ? this.shallow : false : !!shallow this.queued = true ;添加到刷新队列 pushWatcher(this) } } ;Watcher.run() 刷新过程 Watcher.prototype.run = function () { if (this.active) { const value = this.get() if ( value !== this.value ||((isObject(value) || this.deep) && !this.shallow) ) { const oldValue = this.value this.value = value this.cb.call(this.vm, value, oldValue) } this.queued = this.shallow = false } } ;Watcher.evaluate计算Watcher表达式的值 Watcher.prototype.evaluate = function () { const current = Dep.target this.value = this.get() this.dirty = false Dep.target = current } ~~~ >[info] export ~~~ ;(导出)消息订阅者 export default function Watcher{} ~~~ ![](https://box.kancloud.cn/2016-05-06_572bf787b395e.jpg) ### 4-6 array.js(数组监控) >[info] import ~~~ ;(导入) 对象属性定义 import { def } from '../util/index' ~~~ >[info] module ~~~ ;数组原型 const arrayProto = Array.prototype ;数组原型方法 export const arrayMethods = Object.create(arrayProto) ;方法修改 ;[ 'push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse' ] .forEach(function (method) { ;原始方法 const original = arrayProto[method] ;注册对象属性为扩展方法 def(arrayMethods, method, function mutator () { ;参数获取 let i = arguments.length const args = new Array(i) while (i--) { args[i] = arguments[i] } ;原始方法调用 const result = original.apply(this, args) ;数据监听实现 const ob = this.__ob__ let inserted switch (method) { case 'push': inserted = args break case 'unshift': inserted = args break case 'splice': inserted = args.slice(2) break } ;数组数据监听 if (inserted) ob.observeArray(inserted) ;依赖刷新 ob.dep.notify() ;返回结果 return result }) }) ~~~ >[info] export ~~~ ;(导出)数组方法 export const arrayMethods ~~~ ![](https://box.kancloud.cn/2016-05-06_572bf6c0146bf.png)