vue中的響應式資料繫結是通過資料劫持和觀察者模式來實現的。當前學習原始碼為vue2.0
原始碼關鍵目錄
src
|---core
| |---instance
| |---init.js
| |---state.js
| |---observer
| |---dep.js
| |---watcher.js
當我們例項化乙個vue應用的時候,會伴隨著各種的初始化工作,相關的初始化工作**在init.js檔案中
// src/core/instance/init.js
vue.prototype._init = function (options?: object)
在這裡可以看到對state的初始化工作initstate()
// src/core/instance/state.js
export function initstate (vm: component)
可以看到這裡有對各種sate的初始化工作,我們看initdata()
// src/core/instance/state.js
function initdata (vm: component)
if (!isplainobject(data))
process.env.node_env !== 'production' && warn(
'data functions should return an object.',vm)
} // proxy data on instance
const keys = object.keys(data)
const props = vm.$options.props
let i = keys.length
while (i--) " is already declared as a prop. ` +
`use prop default value instead.`,vm)
} else
} // observe data
observe(data)
data.__ob__ && data.__ob__.vmcount++
}
這裡做了一點判斷,判斷data方法是否返回的是乙個物件,以及props中是否有與data中重名的屬性,最後會呼叫observe對data進行監聽,看一下observe
// src/core/observer/index.js
export function observe (value: any): observer | void
let ob: observer | void
if (hasown(value, '__ob__') && value.__ob__ instanceof observer) else if (
observerstate.shouldconvert &&
!config._isserver &&
(array.isarray(value) || isplainobject(value)) &&
object.i***tensible(value) &&
!value._isvue
) return ob
}
可已看到這裡也是做了一點判斷,如果有__ob__屬性的話就用它,或者如果data是陣列或物件或可擴充套件物件的話,就為它新建乙個observer,看一下observer
// src/core/observer/index.js
export class observer else
} /**
* walk through each property and convert them into
* getter/setters. this method should only be called when
* value type is object.
*/walk (obj: object)
} /**
* observe a list of array items.
*/observearray (items: array)
}}
判斷data是不是陣列,如果是陣列就對陣列元素再去呼叫observe方法做同樣的處理,如果不是,就呼叫walk去劫持該資料,對資料的劫持主要再definereactive方法中,正如函式名,讓資料變得響應式。看一下definereactive方法
// src/core/observer/index.js
export function definereactive (
obj: object,
key: string,
val: any,
customsetter?: function
) // cater for pre-defined getter/setters
const getter = property && property.get
const setter = property && property.set
let childob = observe(val)
object.defineproperty(obj, key,
if (array.isarray(value)) }}
return value
},set: function reactivesetter (newval)
if (process.env.node_env !== 'production' && customsetter)
if (setter) else
childob = observe(newval)
dep.notify() // 發布通知}})
}
遍歷狀態,修改狀態的getter和setter,當頁面上對應狀態被首次渲染的時候,會為頁面上每乙個使用到data的地方新建乙個watcher,並將當前watcher儲存到全域性變數dep.target中,在對應data的getter中就會呼叫dep.depend方法,將當前的watcher新增到當前的dep中,乙個dep對應乙個或多個watcher,著取決於,此狀態被使用的數量。當data被修改時,對應的setter就會被觸發,會呼叫對應的dep中的notify方法,通知所有觀察者,進行更新。
這裡出現了兩個定的類:dep和watcher,其中dep管理觀察者,wathcer代表觀察者
先看一下dep
// src/core/observer/dep.js
export default class dep
addsub (sub: watcher)
removesub (sub: watcher)
depend ()
} notify ()
}}
看一下watcher.js
// src/core/observer/watcher.js
export default class watcher
}}...
}
vue的響應式資料繫結主要依賴object.defineproperty和觀察者模式。
在我們新建乙個vue例項的時候,做一系列的初始化工作,這部分的邏輯集中在src
資料夾下的core
資料夾下的instance
和observer
資料夾內
響應式資料繫結是在狀態的初始化階段完成的,在initstate方法中的initdata中進行data的資料繫結。
在initdata中呼叫observe方法,為該data新建乙個observer類,然後最終呼叫為data中的每乙個成員呼叫walk方法,在walk中通過definereactive方法劫持當前資料
在definereactive中通過object.defineproperty去修改資料的getter和setter
在頁面渲染的時候,頁面上每乙個用到data的地方都會生成乙個watcher,並將它儲存到全域性變數dep.target中,watcher改變每乙個觀察者,dep用來管理觀察者。
然後在data的getter中將呼叫dep的depend方法,將dep.target中的watcher新增到此data對應的dep中,完成依賴收集
在data被修改的時候,對應data的setter方法就會被出動,會呼叫dep.notify()方法發布通知,呼叫每個watcher的uptade方法進行更新。
Vue中資料雙向繫結的原理
es5方法 object.defineproperty 物件名,屬性名,配製物件 有兩個缺點 1 一次只能劫持乙個屬性,需要for in去遍歷物件 2 如果在劫持之後有新增了乙個屬性,那這個屬性是沒有被劫持的,需要額外進行劫持操作 for let key in data set value 新增屬性...
vue資料繫結原理
var title hello var num 10 vue中資料繫結是通過set,get屬性實現的,所以不支援es5的瀏覽器就不能甩vue 在元件配置物件中的data中的資料,在元件建立時,都會被作為set,get屬性新增到元件物件上,在set方法中進行了元件的重新渲染,所以每當data中的資料發...
Vue資料雙向繫結的原理
參考 vue資料雙向繫結是通過資料劫持結合發布者 訂閱者模式的方式來實現的。雙向繫結就是檢視上的變化能夠反映到資料上,資料上的變化也能反映到檢視上。如下圖所示 關鍵點在於data如何更新view,因為view更新data其實可以通過事件監聽即可,比如input標籤監聽 input 事件就可以實現了。...