[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)
- 概述
- 框架结构
- 编译入口(\entries)
- web-compiler.js(web编译)
- web-runtime.js(web运行时)
- web-runtime-wih-compiler.js(web编译运行)
- web-server-renderer.js(web服务器渲染)
- 核心实现 (\core)
- index.js(核心入口)
- config.js(核心配置)
- core\util(核心工具)
- core\observer(双向绑定)
- core\vdom(虚拟DOM)
- core\global-api(核心api)
- core\instance(核心实例)
- 模板编译(\compiler)
- compiler\parser(模板解析)
- events.js(事件解析)
- helper.js(解析助手)
- directives\ref.js(ref指令)
- optimizer.js(解析优化)
- codegen.js(渲染生成)
- index.js(模板编译入口)
- web渲染(\platforms\web)
- compiler(web编译目录)
- runtime(web运行时目录)
- server(web服务器目录)
- util(web工具目录)
- 服务器渲染(\server)
- render-stream.js(流式渲染)
- render.js(服务器渲染函数)
- create-renderer.js(创建渲染接口)
- 框架流程
- Vue初始化
- Vue视图数据绑定
- Vue数据变化刷新
- Vue视图操作刷新
- 框架工具
- 基础工具(\shared)
- 模板编译助手
- 核心实例工具
- Web渲染工具
- 基础原理
- dom
- string
- array
- function
- object
- es6
- 模块(Module)
- 类(Class)
- 函数(箭头)
- 字符串(扩展)
- 代理接口(Proxy)
- 数据绑定基础
- 数据绑定实现
- mvvm简单实现
- mvvm简单使用
- vdom算法
- vdom实现
- vue源码分析资料