国产99久久精品_欧美日本韩国一区二区_激情小说综合网_欧美一级二级视频_午夜av电影_日本久久精品视频

最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關鍵字專題關鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
當前位置: 首頁 - 科技 - 知識百科 - 正文

vue中的數據綁定原理的實現

來源:懂視網 責編:小采 時間:2020-11-27 22:12:11
文檔

vue中的數據綁定原理的實現

vue中的數據綁定原理的實現:本文主要介紹了vue中的數據綁定原理的實現,分享給大家,也給自己留個筆記,具體如下: vue中的響應式數據綁定是通過數據劫持和觀察者模式來實現的。當前學習源碼為vue2.0 源碼關鍵目錄 src |---core | |---instance | |---init.js
推薦度:
導讀vue中的數據綁定原理的實現:本文主要介紹了vue中的數據綁定原理的實現,分享給大家,也給自己留個筆記,具體如下: vue中的響應式數據綁定是通過數據劫持和觀察者模式來實現的。當前學習源碼為vue2.0 源碼關鍵目錄 src |---core | |---instance | |---init.js

本文主要介紹了vue中的數據綁定原理的實現,分享給大家,也給自己留個筆記,具體如下:


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) {
 ...
 initLifecycle(vm)
 initEvents(vm)
 callHook(vm, 'beforeCreate')
 initState(vm)
 callHook(vm, 'created')
 initRender(vm)
}

在這里可以看到對state的初始化工作initState()

// src/core/instance/state.js

export function initState (vm: Component) {
 vm._watchers = []
 initProps(vm)
 initData(vm)
 initComputed(vm)
 initMethods(vm)
 initWatch(vm)
}

可以看到這里有對各種sate的初始化工作,我們看initData()

// src/core/instance/state.js

function initData (vm: Component) {
 let data = vm.$options.data
 data = vm._data = typeof data === 'function'
 ? data.call(vm)
 : data || {}
 if (!isPlainObject(data)) {
 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--) {
 if (props && hasOwn(props, keys[i])) {
 process.env.NODE_ENV !== 'production' && warn(
 `The data property "${keys[i]}" is already declared as a prop. ` +
 `Use prop default value instead.`,
 vm
 )
 } else {
 proxy(vm, keys[i])
 }
 }
 // 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 {
 if (!isObject(value)) {
 return
 }
 let ob: Observer | void
 if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) {
 ob = value.__ob__
 } else if (
 observerState.shouldConvert &&
 !config._isServer &&
 (Array.isArray(value) || isPlainObject(value)) &&
 Object.isExtensible(value) &&
 !value._isVue
 ) {
 ob = new Observer(value)
 }
 return ob
}

可已看到這里也是做了一點判斷,如果有__ob__屬性的話就用它,或者如果data是數組或對象或可擴展對象的話,就為它新建一個Observer,看一下Observer

// src/core/observer/index.js

export class Observer {
 value: any;
 dep: Dep;
 vmCount: number; // number of vms that has this object as root $data

 constructor (value: any) {
 this.value = value
 this.dep = new Dep()
 this.vmCount = 0
 def(value, '__ob__', this)
 if (Array.isArray(value)) {
 const augment = hasProto
 ? protoAugment
 : copyAugment
 augment(value, arrayMethods, arrayKeys)
 this.observeArray(value)
 } else {
 this.walk(value)
 }
 }

 /**
 * Walk through each property and convert them into
 * getter/setters. This method should only be called when
 * value type is Object.
 */
 walk (obj: Object) {
 const keys = Object.keys(obj)
 for (let i = 0; i < keys.length; i++) {
 defineReactive(obj, keys[i], obj[keys[i]])
 }
 }

 /**
 * Observe a list of Array items.
 */
 observeArray (items: Array<any>) {
 for (let i = 0, l = items.length; i < l; i++) {
 observe(items[i])
 }
 }
}

判斷data是不是數組,如果是數組就對數組元素再去調用observe方法做同樣的處理,如果不是,就調用walk去劫持該數據,對數據的劫持主要再defineReactive方法中,正如函數名,讓數據變得響應式。看一下defineReactive方法

// src/core/observer/index.js

export function defineReactive (
 obj: Object,
 key: string,
 val: any,
 customSetter?: Function
) {
 const dep = new Dep()
// data中的每一個成員都有一個對應的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 (Array.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 (process.env.NODE_ENV !== 'production' && customSetter) {
 customSetter()
 }
 if (setter) {
 setter.call(obj, newVal)
 } else {
 val = newVal
 }
 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 {
 static target: ?Watcher;
 id: number;
 subs: Array<Watcher>;

 constructor () {
 this.id = uid++
 this.subs = []
 }

 addSub (sub: Watcher) {
 this.subs.push(sub)
 }

 removeSub (sub: Watcher) {
 remove(this.subs, sub)
 }

 depend () {
 if (Dep.target) {
// 調用當前target,也就是正在處理的watcher的addDep方法,并把此Dep傳進去
 Dep.target.addDep(this)
 }
 }

 notify () {
 // stablize the subscriber list first
 const subs = this.subs.slice()
 for (let i = 0, l = subs.length; i < l; i++) {
 subs[i].update()
 }
 }
}

看一下watcher.js

// src/core/observer/watcher.js

export default class Watcher {
...
 addDep (dep: Dep) {
 const id = dep.id
 if (!this.newDepIds.has(id)) {
 this.newDepIds.add(id)
 this.newDeps.push(dep)
 if (!this.depIds.has(id)) {
 // 將當前watcher添加到當前的Dep中
 dep.addSub(this)
 }
 }
 }
...
}

總結

vue的響應式數據綁定主要依賴Object.defineProperty和觀察者模式。

  1. 在我們新建一個vue實例的時候,做一系列的初始化工作,這部分的邏輯集中在src文件夾下的core文件夾下的instance和observer文件夾內
  2. 響應式數據綁定是在狀態的初始化階段完成的,在initState方法中的initData中進行data的數據綁定。
  3. 在initData中調用observe方法,為該data新建一個Observer類,然后最終調用為data中的每一個成員調用walk方法,在walk中通過defineReactive方法劫持當前數據
  4. 在defineReactive中通過Object.defineProperty去修改數據的getter和setter
  5. 在頁面渲染的時候,頁面上每一個用到data的地方都會生成一個watcher,并將它保存到全局變量Dep.target中,watcher改變每一個觀察者,Dep用來管理觀察者。
  6. 然后在data的getter中將調用Dep的depend方法,將Dep.target中的watcher添加到此data對應的Dep中,完成依賴收集
  7. 在data被修改的時候,對應data的setter方法就會被出動,會調用Dep.notify()方法發布通知,調用每個watcher的uptade方法進行更新。

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

文檔

vue中的數據綁定原理的實現

vue中的數據綁定原理的實現:本文主要介紹了vue中的數據綁定原理的實現,分享給大家,也給自己留個筆記,具體如下: vue中的響應式數據綁定是通過數據劫持和觀察者模式來實現的。當前學習源碼為vue2.0 源碼關鍵目錄 src |---core | |---instance | |---init.js
推薦度:
標簽: 綁定 中的 數據
  • 熱門焦點

最新推薦

猜你喜歡

熱門推薦

專題
Top
主站蜘蛛池模板: 在线观看亚洲专区 | 亚洲日本在线观看 | 99精品欧美一区二区三区综合在线 | 国产又大又粗又猛又爽的视频 | 国产欧美第一页 | 香蕉依人 | 91精品国产91久久久久久 | 国产成人精品一区二区不卡 | 精品国产一区二区三区久久久狼 | 亚洲国产精品综合久久一线 | 国产精品123| 免费a一毛片 | 亚洲欧美另类日本 | 国产精品电影一区二区三区 | 亚洲精品乱码久久久久久 | 亚洲欧洲视频在线 | 欧美高清一区二区 | b毛片| 一级特黄牲大片免费视频 | 精品久久久久久久 | 图片专区亚洲欧美另类 | 国产91成人精品亚洲精品 | 国产日产精品_国产精品毛片 | 日本另类αv欧美另类aⅴ | 亚洲国产综合久久精品 | 一区二区三区四区视频 | 国产精品天天看大片特色视频 | 日本a黄 | 国产精品久久亚洲一区二区 | 亚洲视频在线免费观看 | 亚洲欧美日韩色图 | 香蕉久久精品 | 骚b视频| 看全色黄大色大片免费久久久 | 视频一区久久 | 欧美影欧美影院免费观看视频 | 久久精品国产精品亚洲综合 | 国产黄色片一级 | 国产免费一级片 | 全免费毛片在线播放 | 欧美日韩一二区 |