• <fieldset id="8imwq"><menu id="8imwq"></menu></fieldset>
  • <bdo id="8imwq"><input id="8imwq"></input></bdo>
    最新文章專題視頻專題問答1問答10問答100問答1000問答2000關(guān)鍵字專題1關(guān)鍵字專題50關(guān)鍵字專題500關(guān)鍵字專題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關(guān)鍵字專題關(guān)鍵字專題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
    當(dāng)前位置: 首頁 - 科技 - 知識百科 - 正文

    vue中的數(shù)據(jù)綁定原理的實(shí)現(xiàn)

    來源:懂視網(wǎng) 責(zé)編:小采 時間:2020-11-27 22:12:11
    文檔

    vue中的數(shù)據(jù)綁定原理的實(shí)現(xiàn)

    vue中的數(shù)據(jù)綁定原理的實(shí)現(xiàn):本文主要介紹了vue中的數(shù)據(jù)綁定原理的實(shí)現(xiàn),分享給大家,也給自己留個筆記,具體如下: vue中的響應(yīng)式數(shù)據(jù)綁定是通過數(shù)據(jù)劫持和觀察者模式來實(shí)現(xiàn)的。當(dāng)前學(xué)習(xí)源碼為vue2.0 源碼關(guān)鍵目錄 src |---core | |---instance | |---init.js
    推薦度:
    導(dǎo)讀vue中的數(shù)據(jù)綁定原理的實(shí)現(xiàn):本文主要介紹了vue中的數(shù)據(jù)綁定原理的實(shí)現(xiàn),分享給大家,也給自己留個筆記,具體如下: vue中的響應(yīng)式數(shù)據(jù)綁定是通過數(shù)據(jù)劫持和觀察者模式來實(shí)現(xiàn)的。當(dāng)前學(xué)習(xí)源碼為vue2.0 源碼關(guān)鍵目錄 src |---core | |---instance | |---init.js

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


    vue中的響應(yīng)式數(shù)據(jù)綁定是通過數(shù)據(jù)劫持和觀察者模式來實(shí)現(xiàn)的。當(dāng)前學(xué)習(xí)源碼為vue2.0

    源碼關(guān)鍵目錄

    src
    |---core
    | |---instance
    | |---init.js
    | |---state.js
    | |---observer
    | |---dep.js
    | |---watcher.js
    

    當(dāng)我們實(shí)例化一個vue應(yīng)用的時候,會伴隨著各種的初始化工作,相關(guān)的初始化工作代碼在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++
    }
    
    

    這里做了一點(diǎn)判斷,判斷data方法是否返回的是一個對象,以及props中是否有與data中重名的屬性,最后會調(diào)用observe對data進(jìn)行監(jiān)聽,看一下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
    }
    
    

    可已看到這里也是做了一點(diǎn)判斷,如果有__ob__屬性的話就用它,或者如果data是數(shù)組或?qū)ο蠡蚩蓴U(kuò)展對象的話,就為它新建一個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是不是數(shù)組,如果是數(shù)組就對數(shù)組元素再去調(diào)用observe方法做同樣的處理,如果不是,就調(diào)用walk去劫持該數(shù)據(jù),對數(shù)據(jù)的劫持主要再defineReactive方法中,正如函數(shù)名,讓數(shù)據(jù)變得響應(yīng)式。看一下defineReactive方法

    // src/core/observer/index.js
    
    export function defineReactive (
     obj: Object,
     key: string,
     val: any,
     customSetter?: Function
    ) {
     const dep = new Dep()
    // data中的每一個成員都有一個對應(yīng)的Dep,在此閉包創(chuàng)建。
    
     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() // 發(fā)布通知
     }
     })
    }
    
    

    遍歷狀態(tài),修改狀態(tài)的getter和setter,當(dāng)頁面上對應(yīng)狀態(tài)被首次渲染的時候,會為頁面上每一個使用到data的地方新建一個watcher,并將當(dāng)前watcher保存到全局變量Dep.target中,在對應(yīng)data的getter中就會調(diào)用Dep.depend方法,將當(dāng)前的watcher添加到當(dāng)前的Dep中,一個Dep對應(yīng)一個或多個watcher,著取決于,此狀態(tài)被使用的數(shù)量。當(dāng)data被修改時,對應(yīng)的setter就會被觸發(fā),會調(diào)用對應(yīng)的Dep中的notify方法,通知所有觀察者,進(jìn)行更新。

    這里出現(xiàn)了兩個定的類: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) {
    // 調(diào)用當(dāng)前target,也就是正在處理的watcher的addDep方法,并把此Dep傳進(jìn)去
     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)) {
     // 將當(dāng)前watcher添加到當(dāng)前的Dep中
     dep.addSub(this)
     }
     }
     }
    ...
    }
    
    

    總結(jié)

    vue的響應(yīng)式數(shù)據(jù)綁定主要依賴Object.defineProperty和觀察者模式。

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

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

    文檔

    vue中的數(shù)據(jù)綁定原理的實(shí)現(xiàn)

    vue中的數(shù)據(jù)綁定原理的實(shí)現(xiàn):本文主要介紹了vue中的數(shù)據(jù)綁定原理的實(shí)現(xiàn),分享給大家,也給自己留個筆記,具體如下: vue中的響應(yīng)式數(shù)據(jù)綁定是通過數(shù)據(jù)劫持和觀察者模式來實(shí)現(xiàn)的。當(dāng)前學(xué)習(xí)源碼為vue2.0 源碼關(guān)鍵目錄 src |---core | |---instance | |---init.js
    推薦度:
    標(biāo)簽: 綁定 中的 數(shù)據(jù)
    • 熱門焦點(diǎn)

    最新推薦

    猜你喜歡

    熱門推薦

    專題
    Top
    主站蜘蛛池模板: 免费视频成人国产精品网站| 亚洲精品无码久久不卡| 精品无码久久久久久国产| 国产精品亚韩精品无码a在线| 国产精品综合久成人| 国产成人精品高清在线观看99| 欧美成人精品第一区二区三区| 欧美精品免费线视频观看视频| 亚洲AV第一页国产精品| 国模和精品嫩模私拍视频| 久久精品中文字幕久久| 久久99国产精品尤物| 无码精品人妻一区| 精品久久久久久99人妻| 91国内揄拍国内精品情侣对白| 精品一区二区三区在线成人| 亚洲午夜国产精品无码老牛影视| 国内精品久久久久久久coent| 亚洲第一精品在线视频| 国产suv精品一区二区33| 青草国产精品久久久久久| 亚洲国产精品一区二区三区久久 | 久久国产精品免费一区| 99久久国产热无码精品免费久久久久| 国产AV国片精品| 久热这里只有精品视频6| 一本一道精品欧美中文字幕| 欧美成人精品一区二三区在线观看| 成人精品视频成人影院| 一级成人精品h| 亚洲国产精品线在线观看| 国产亚洲美女精品久久久久狼| 国产成人久久精品激情| 精品欧洲AV无码一区二区男男| 骚片AV蜜桃精品一区| 午夜DY888国产精品影院| 亚洲一区二区三区国产精品| 亚洲精品无码久久不卡| 一区二区日韩国产精品| 亚洲愉拍99热成人精品热久久| 亚洲精品美女久久久久99|