[TOC]
****
## 1 Vue的數據綁定
>[info] 數據綁定的實現分為**數據層劫持**與**UI層事件注冊**。
>[info] 這里分析vue對數據層劫持的實現機制
## 2 實現observer(數據觀察者)
>[info] 對observe對象的屬性進程set/get操作劫持
>[info] 實現劫持后對Observer對象屬性的set與get操作可以觸發響應操作,
>[info] 其中的操作包括UI層的更新與其他數據的刷新
~~~
export default class Observer{
constructor(value){
;屬性value獲取
this.value = value
;屬性遍歷
this.walk(value)
}
;遍歷操作
walk(value){
;獲取屬性value的keys
var keys = Object.keys(value)
;遍歷keys
keys.foreach(
;將key對應的值轉換為劫持屬性
key=>this.convert(key,value[key])
)
}
;轉換屬性為劫持屬性
convert(key,val){
defineReactive(this.value,key,val)
}
;屬性轉換操作
expot function defineReactive(obj,key,val){
;val遞歸遍歷
var childOb = observe(val)
;注冊為劫持屬性
Object.defineProperty(obj,key,val){
enumerable : true,
configurable : true,
get:() => val,
set:newVal=>{
childOb = observe(newVal)
}
}
}
;屬性遞歸操作
export function observe(value,vm){
if(!value||typeof value ! = 'object'){
return
}
;生成數據監視器observer
return new Observer(value)
}
}
~~~
## 3 實現Dep(消息訂閱器)
>[info] set操作會廣播消息到訂閱器數組的所有訂閱者
>[info] 消息訂閱器數組的訂閱者將會進行刷新操作。
>[info] 消息訂閱器中的訂閱者可以是UI層也可以是數據層
~~~
;Dep實現
export default class Dep{
constructor(){
this.subs = []
}
addSub(sub){
this.subs.push(sub)
}
notify(){
this.subs.forEach(sub=>sub.update())
}
}
~~~
~~~
;注冊Dep(消息訂閱器)到observer(數據觀察者)
export function defineReactive(obj,key,val){
;創建訂閱器數組
var dep = new Dep()
;注冊為劫持屬性
var childOb = observe(val)
Object.defineProperty(obj,key,{
enumberable:true,
configurable:true,
get:()=>val,
set:newVal =>{
;舊值
var value = val
;比較新舊值
if(newVal === value){
return
}
;值不相等進行處理
val = newVal
childOb = observe(newVal)
;廣播數據更新到消息訂閱者數組
dep.notify()
}
})
}
~~~
## 4 實現Watcher(消息訂閱者)
>[info] 消息訂閱者存儲在消息訂閱器數組中
>[info] 數據層的set操作會廣播消息到訂閱器數組
>[info] 訂閱器數組中的訂閱者會進行自我刷新操作
>[info] 消息訂閱者可以是數據層也可以是UI層
~~~
;實現消息訂閱者
export default class Watcher{
constructor(vm,expOrFn,cb){
this.cb = cb
this.vm = vm
this.expOrFn = expOrFn
this.value = this.get()
}
;消息訂閱者刷新操作
update(){
this.run()
}
;刷新運行過程
run(){
const value = this.get()
if( vakue ! == this.value){
this.value = value
this.cb.call(this.vm)
}
}
;獲取指令表達式的值
get(){
const value = this.vm._data[this.expOrFn]
return value
}
}
~~~
>[info] 現在需要將消息訂閱者注冊到消息訂閱器中
>[info] 這樣數據層set層廣播消息到消息訂閱器數組
>[info] 消息訂閱者可接受消息進行相應刷新操作
>[info] 注冊的關鍵在Object.defineProperty的get()被調用時
>[info] Watcher的get()會調用數據層的get()。
>[info] 觸發get劫持,注冊Watcher到Dep數組中
>[info] 為了判斷是否在Watcher中進行get,需要設置一個狀態位
~~~
;修改后的watcher
export default class Watcher{
....
get(){
;設置狀態標志
Dep.target = this
;調用Object.defineProperty()注冊的get劫持
const value = this.vm._data[this.expOrFn]
;還原狀態標識
Dep.target = null
return value
}
....
}
~~~
~~~
;修改后的definReactive()
export function defineReactive(obj,key,val){
;創建消息訂閱器數組
var dep = new Dep()
;修改為劫持屬性
var childOb = observe(val)
Object.defineProperty(obj,key,{
enumberable : true,
configurable : true,
get:() => {
;檢查是否watch的get,注冊到Dep中
if(Dep.target){
dep.addSub(Dep.target)
}
return val
},
set:newVal => {
var value = val
;值相等直接返回
if(newVal === value){
return
}
;值不相等觸發刷新操作
val = newVal
childOb = observe(newVal)
dep.ontify()
}
})
}
~~~
## 5 總結
>[info] 數據綁定實現了對數據層set與get的劫持與刷新操作關聯
>[info]Observer實現對數據屬性的set/get的劫持
>[info]Dep實現對set操作的消息廣播數組的管理
>[info]Watcher對應特定消息的訂閱者,可以實現為數據層刷新或者UI層刷新
## 6 參考
[vue的數據綁定實現](https://segmentfault.com/a/1190000004384515)
- 概述
- 框架結構
- 編譯入口(\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源碼分析資料