日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 前端技术 > vue >内容正文

vue

vue响应式原理

發(fā)布時(shí)間:2023/12/10 vue 49 豆豆
生活随笔 收集整理的這篇文章主要介紹了 vue响应式原理 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

vue響應(yīng)式原理

initState

new Vue() => _init() => initState:

function initState (vm: Component) {vm._watchers = []const opts = vm.$optionsif (opts.props) initProps(vm, opts.props)if (opts.methods) initMethods(vm, opts.methods)if (opts.data) {initData(vm)} else {observe(vm._data = {}, true /* asRootData */)}if (opts.computed) initComputed(vm, opts.computed)if (opts.watch && opts.watch !== nativeWatch) {initWatch(vm, opts.watch)} }

判斷該vue實(shí)例是否存在props、methods、data、computed、watch進(jìn)行調(diào)用相應(yīng)的初始化函數(shù)

initProps與initData

主要工作是調(diào)用defineProperty給屬性分別掛載get(觸發(fā)該鉤子時(shí),會(huì)將當(dāng)前屬性的dep實(shí)例推入當(dāng)前的Dep.target也就是當(dāng)前watcher的deps中即它訂閱的依賴,Dep.target下文會(huì)講到。且該dep實(shí)例也會(huì)將當(dāng)前watcher即觀察者推入其subs數(shù)組中)、set方法(通知該依賴subs中所有的觀察者watcher去調(diào)用他們的update方法)。

initComputed

它的作用是將computed對(duì)象中所有的屬性遍歷,并給該屬性new一個(gè)computed watcher(計(jì)算屬性中定義了個(gè)dep依賴,給需要使用該計(jì)算屬性的watcher訂閱)。也會(huì)通過(guò)調(diào)用defineProperty給computed掛載get(get方法)、set方法(set方法會(huì)判斷是否傳入,如果沒(méi)傳入會(huì)設(shè)置成noop空函數(shù))
computed屬性的get方法是下面函數(shù)的返回值函數(shù)

function createComputedGetter (key) {return function computedGetter () {const watcher = this._computedWatchers && this._computedWatchers[key]if (watcher) {watcher.depend()return watcher.evaluate()}} }

注意其中的watcher.depend(),該方法讓用到該屬性的watcher觀察者訂閱該watcher中的依賴,且該計(jì)算屬性watcher會(huì)將訂閱它的watcher推入他的subs中(當(dāng)計(jì)算屬性值改變的時(shí)候,通知訂閱他的watcher觀察者)
watcher.evaluate(),該方法是通過(guò)調(diào)用watcher的get方法(其中需要注意的是watcher的get方法會(huì)調(diào)用pushTarget將之前的Dep.target實(shí)例入棧,并設(shè)置Dep.target為該computed watcher,被該計(jì)算屬性依賴的響應(yīng)式屬性會(huì)將該computed watcher推入其subs中,所以當(dāng)被依賴的響應(yīng)式屬性改變時(shí),會(huì)通知訂閱他的computed watcher,computed watcher 再通知訂閱該計(jì)算屬性的watcher調(diào)用update方法),get方法中調(diào)用計(jì)算屬性key綁定的handler函數(shù)計(jì)算出值。

initWatch

該watcher 為user watcher(開(kāi)發(fā)人員自己在組件中自定義的)。
initWatch的作用是遍歷watch中的屬性,并對(duì)每個(gè)watch監(jiān)聽(tīng)的屬性調(diào)用定義的$watch

Vue.prototype.$watch = function (expOrFn: string | Function,cb: any,options?: Object): Function {const vm: Component = thisif (isPlainObject(cb)) {return createWatcher(vm, expOrFn, cb, options)}options = options || {}options.user = true // 代表該watcher是用戶自定義watcherconst watcher = new Watcher(vm, expOrFn, cb, options)if (options.immediate) {cb.call(vm, watcher.value)}return function unwatchFn () {watcher.teardown()}}

代碼中調(diào)用new Watcher的時(shí)候,也會(huì)同render watcher一樣,執(zhí)行下watcher的get方法,調(diào)用pushTarget將當(dāng)前user watcher賦值給Dep.target,get()中value = this.getter.call(vm, vm)這個(gè)語(yǔ)句會(huì)觸發(fā)該自定義watcher監(jiān)聽(tīng)的響應(yīng)式屬性的get方法,并將當(dāng)前的user watcher推入該屬性依賴的subs中,所以當(dāng)user watcher監(jiān)聽(tīng)的屬性set觸發(fā)后,通知訂閱該依賴的watcher去觸發(fā)update,也就是觸發(fā)該watch綁定的key對(duì)應(yīng)的handler。然后就是調(diào)用popTarget出棧并賦值給Dep.target。

$mount

initState初始化工作大致到這里過(guò),接下去會(huì)執(zhí)行$mount開(kāi)始渲染工作
$mount主要工作:new了一個(gè)渲染W(wǎng)atcher,并將updateCompent作為callback傳遞進(jìn)去并執(zhí)行

updateComponent = () => {vm._update(vm._render(), hydrating)} new Watcher(vm, updateComponent, noop, {before () {if (vm._isMounted) {callHook(vm, 'beforeUpdate')}}}, true /* isRenderWatcher */)

三種watcher中new Watcher的時(shí)候,只有computed watcher不會(huì)一開(kāi)始就執(zhí)行它的get()方法。$mount里面new的這個(gè)render watcher會(huì)調(diào)用get()方法,調(diào)用pushTarget將當(dāng)前render watcher賦值給Dep.target。接下去重頭戲來(lái)了,調(diào)用updateComponent,該方法會(huì)執(zhí)行vm._update(vm._render(), hydrating),其中render函數(shù)會(huì)觸發(fā)html中使用到的響應(yīng)式屬性的get鉤子。get鉤子會(huì)讓該響應(yīng)式屬性的依賴實(shí)例dep將當(dāng)前的render watcher推入其subs數(shù)組中,所以當(dāng)依賴的響應(yīng)式屬性改變之后,會(huì)遍歷subs通知訂閱它的watcher去調(diào)用update()。

例子

可能大家對(duì)watcher和dep調(diào)來(lái)調(diào)去一頭霧水,我講個(gè)實(shí)例

<div id="app"><div>{{a}}</div><div>{}</div></div> new Vue({el: "#app",data() {return {a:1,}},computed:{b() {return a+1}}, })

我直接從渲染開(kāi)始講,只講跟dep跟watcher有關(guān)的
$mount:new一個(gè)渲染watcher(watcher的get方法中會(huì)將渲染watcher賦值給Dep.target)的時(shí)候會(huì)觸發(fā) vm._update(vm._render(), hydrating),render的時(shí)候會(huì)獲取html中用到的響應(yīng)式屬性,上面例子中先用到了a,這時(shí)會(huì)觸發(fā)a的get鉤子,其中dep.depend()會(huì)將當(dāng)前的渲染watcher推入到a屬性的dep的subs數(shù)組中。
接下去繼續(xù)執(zhí)行,訪問(wèn)到b(b是計(jì)算屬性的值),會(huì)觸發(fā)計(jì)算屬性的get方法。計(jì)算屬性的get方法是調(diào)用createComputedGetter函數(shù)后的返回函數(shù)computedGetter,computedGetter函數(shù)中會(huì)執(zhí)行watcher.depend()。Watcher的depend方法是專門留給computed watcher使用的。剛才上面說(shuō)過(guò)了除了computed watcher,其他兩種watcher在new 完之后都會(huì)執(zhí)行他們的get方法,那么computed watcher在new完之后干嘛呢,它會(huì)new一個(gè)dep?;氐絼偛耪f(shuō)的專門為computed watcher開(kāi)設(shè)的方法watcher.depend(),他的作用是執(zhí)行this.dep.depend()(computed watcher定義的dep就是在這里使用到的)。this.dep.depend()會(huì)讓當(dāng)前的渲染watcher訂閱該計(jì)算屬性依賴,該計(jì)算屬性也會(huì)將渲染watcher推入到它自己的subs([render watcher])中,當(dāng)計(jì)算屬性的值修改之后會(huì)通知subs中的watcher調(diào)用update(),所以計(jì)算屬性值變了頁(yè)面能刷新?;氐角懊嬲f(shuō)的觸發(fā)b計(jì)算屬性的get鉤子那里,get鉤子最后會(huì)執(zhí)行watcher.evaluate(),watcher.evaluate()會(huì)執(zhí)行computed watcher的get()方法。這時(shí)候重點(diǎn)來(lái)了,會(huì)將Dep.target(render watcher)推入targetStack棧中(存入之后以便待會(huì)兒取出繼續(xù)用),然后將這個(gè)計(jì)算屬性的computed watcher賦值給Dep.target。get方法中value = this.getter.call(vm, vm),會(huì)執(zhí)行computed屬性綁定的handler。如上面例子中return a + 1。使用了a那么就一定會(huì)觸發(fā)a的get鉤子,get鉤子又會(huì)調(diào)用dep.depend(),dep.depend()會(huì)讓computed watcher將dep存入它的deps數(shù)組中,a的dep會(huì)將當(dāng)前的Dep.target(computed watcher)存入其subs數(shù)組中,當(dāng)前例子中a的subs中就會(huì)是[render watcher,computed watcher],所以a值變化會(huì)遍歷a的subs中的watcher調(diào)用update()方法,html中用到的a會(huì)刷新,計(jì)算屬性watcher調(diào)用update()方法會(huì)通知他自己的subs([render watcher])中render watcher去調(diào)用update方法,html中用到的計(jì)算屬性b才會(huì)刷新dom(這里提個(gè)醒,我只是粗略的講,計(jì)算屬性依賴的屬性變化后他不一定會(huì)觸發(fā)更新,他會(huì)比較計(jì)算完之后的值是否變化)。computed watcher的get()方法最后會(huì)調(diào)用popTarget(),將之前存入render watcher出棧并賦值給Dep.target,這時(shí)候我例子中targetStack就變成空數(shù)組了。render watcher的get方法執(zhí)行到最后也會(huì)出棧,這時(shí)候會(huì)將Dep.target賦值會(huì)空。

總結(jié)

以上是生活随笔為你收集整理的vue响应式原理的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。