摘要:執(zhí)行當(dāng)時傳入的回調(diào),并將新值與舊值一并傳入。文章鏈接源碼分析系列源碼分析系列之環(huán)境搭建源碼分析系列之入口文件分析源碼分析系列之響應(yīng)式數(shù)據(jù)一源碼分析系列之響應(yīng)式數(shù)據(jù)二源碼分析系列之響應(yīng)式數(shù)據(jù)三
前言
上一節(jié)著重講述了initComputed中的代碼,以及數(shù)據(jù)是如何從computed中到視圖層的,以及data修改后如何作用于computed。這一節(jié)主要記錄initWatcher中的內(nèi)容。
正文 demo修改之前的new Vue(options)的options中,我們可以觀察到computed,data,但是對于watch是沒法演示的,所以我們在代碼中加入一段可以觀察到watch初始化以及效果的代碼。
{ watch: { a(newV,oldV) { console.log(`${oldV} -> ${newV}`); } } }
依舊是觀察a這個變量,當(dāng)點(diǎn)擊+1按鈕時候,即可讓a變化。
入口if (opts.watch && opts.watch !== nativeWatch) { initWatch(vm, opts.watch); }initWatch
function initWatch (vm: Component, watch: Object) { for (const key in watch) { // 拿到watch中相關(guān)的處理邏輯 const handler = watch[key] // 如果是個數(shù)組,就挨個創(chuàng)建watcher if (Array.isArray(handler)) { for (let i = 0; i < handler.length; i++) { createWatcher(vm, key, handler[i]) } } else { // 否則直接初始化,我們此次例子中會直接走這里 // createWatcher(vm, a, fn) createWatcher(vm, key, handler) } } }createWatcher
function createWatcher ( vm: Component, keyOrFn: string | Function, handler: any, options?: Object ) { // 這里只是對不同創(chuàng)建形式的標(biāo)準(zhǔn)化。 if (isPlainObject(handler)) { options = handler handler = handler.handler } if (typeof handler === "string") { handler = vm[handler] } // 最終這里是真正監(jiān)聽值變化的地方。 // $watch(a, handle, undefined); return vm.$watch(keyOrFn, handler, options) }vm.$watch
Vue.prototype.$watch = function ( expOrFn: string | Function, cb: any, options?: Object ): Function { const vm: Component = this if (isPlainObject(cb)) { return createWatcher(vm, expOrFn, cb, options) } options = options || {} options.user = true // 主要是這里創(chuàng)建一個觀察者 // new Watcher(vm, "a", handle, {user: true}) const watcher = new Watcher(vm, expOrFn, cb, options) if (options.immediate) { cb.call(vm, watcher.value) } return function unwatchFn () { watcher.teardown() } }new Watcher
watcher,即觀察者,是我們多次提到的一個東西。這里主要強(qiáng)調(diào)的是watcher.get()中的內(nèi)容。
class Watcher { constructor ( vm: Component, expOrFn: string | Function, cb: Function, options?: Object ) { // 一堆初始化信息 if (options) { this.deep = !!options.deep this.user = !!options.user this.lazy = !!options.lazy this.sync = !!options.sync } else { this.deep = this.user = this.lazy = this.sync = false } this.value = this.lazy ? undefined : this.get() } get () { // 將當(dāng)前watcher設(shè)為Dep.target方便后面訪問a的getter時候, // 設(shè)定為a的依賴 pushTarget(this) let value const vm = this.vm try { // 求a的值。并把當(dāng)前watcher加入a的依賴中。 value = this.getter.call(vm, vm) } catch (e) { if (this.user) { handleError(e, vm, `getter for watcher "${this.expression}"`) } else { throw e } } finally { // "touch" every property so they are all tracked as // dependencies for deep watching if (this.deep) { traverse(value) } popTarget() this.cleanupDeps() } return value } }run watcher
到上一步,監(jiān)聽a的watcher已經(jīng)初始化完畢了,當(dāng)a因?yàn)辄c(diǎn)擊鼠標(biāo)變化時候,會觸發(fā)這個watcher的變化。執(zhí)行watcher的run方法,我們繼續(xù)來看下run方法里的內(nèi)容。
class Watcher { run () { if (this.active) { // 求a的最新值。 const value = this.get() if ( value !== this.value || // Deep watchers and watchers on Object/Arrays should fire even // when the value is the same, because the value may // have mutated. isObject(value) || this.deep ) { // 當(dāng)a變的時候,將舊值賦給oldValue。 const oldValue = this.value // this.value賦予最新的值。 this.value = value // 用戶定義的watch調(diào)用時加入try,catch。 if (this.user) { try { // 執(zhí)行當(dāng)時傳入的回調(diào),并將新值與舊值一并傳入。 this.cb.call(this.vm, value, oldValue) } catch (e) { handleError(e, this.vm, `callback for watcher "${this.expression}"`) } } else { this.cb.call(this.vm, value, oldValue) } } } } }總結(jié)
至此,watch,監(jiān)聽屬性的這一部分已經(jīng)完結(jié),本質(zhì)上就是對于每個監(jiān)聽的屬性,創(chuàng)建一個watcher。當(dāng)watcher改變時候,會觸發(fā)開發(fā)者定義的回調(diào)。通過前兩篇文章的學(xué)習(xí),這篇應(yīng)該算是很理解的內(nèi)容。
文章鏈接vue源碼分析系列
vue源碼分析系列之debug環(huán)境搭建
vue源碼分析系列之入口文件分析
vue源碼分析系列之響應(yīng)式數(shù)據(jù)(一)
vue源碼分析系列之響應(yīng)式數(shù)據(jù)(二)
vue源碼分析系列之響應(yīng)式數(shù)據(jù)(三)
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/101770.html
摘要:代碼初始化部分一個的時候做了什么當(dāng)我們一個時,實(shí)際上執(zhí)行了的構(gòu)造函數(shù),這個構(gòu)造函數(shù)內(nèi)部掛載了很多方法,可以在我的上一篇文章中看到。合并構(gòu)造函數(shù)上掛載的與當(dāng)前傳入的非生產(chǎn)環(huán)境,包裝實(shí)例本身,在后期渲染時候,做一些校驗(yàn)提示輸出。 概述 在使用vue的時候,data,computed,watch是一些經(jīng)常用到的概念,那么他們是怎么實(shí)現(xiàn)的呢,讓我們從一個小demo開始分析一下它的流程。 dem...
摘要:中引入了中的中引入了中的中,定義了的構(gòu)造函數(shù)中的原型上掛載了方法,用來做初始化原型上掛載的屬性描述符,返回原型上掛載的屬性描述符返回原型上掛載與方法,用來為對象新增刪除響應(yīng)式屬性原型上掛載方法原型上掛載事件相關(guān)的方法。 入口尋找 入口platforms/web/entry-runtime-with-compiler中import了./runtime/index導(dǎo)出的vue。 ./r...
摘要:目標(biāo)是為了可以調(diào)試版本的,也就是下的源碼,所以主要是的開啟。結(jié)語至此就可以開心的研究源碼啦。文章鏈接源碼分析系列源碼分析系列之入口文件分析源碼分析系列之響應(yīng)式數(shù)據(jù)一源碼分析系列之響應(yīng)式數(shù)據(jù)二 概述 為了探究vue的本質(zhì),所以想debug一下源碼,但是怎么開始是個問題,于是有了這樣一篇記錄。目標(biāo)是為了可以調(diào)試es6版本的,也就是src下的源碼,所以主要是sourceMap的開啟。原文來自...
閱讀 1785·2023-04-26 00:47
閱讀 1543·2021-11-11 16:55
閱讀 2597·2021-09-27 14:04
閱讀 3548·2021-09-22 15:58
閱讀 3554·2021-07-26 23:38
閱讀 2129·2019-08-30 13:47
閱讀 1979·2019-08-30 13:15
閱讀 1142·2019-08-29 17:09