vue中的資料繫結原理

2021-09-13 15:13:47 字數 4469 閱讀 6583

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資料夾下的instanceobserver資料夾內

響應式資料繫結是在狀態的初始化階段完成的,在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 事件就可以實現了。...