欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

vue定義在computed的變量無法更新問題及解決

 更新時間:2023年01月10日 16:43:59   作者:reisaru  
這篇文章主要介紹了vue定義在computed的變量無法更新問題及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

vue定義在computed的變量無法更新

情境是這是線上商城的詳情頁面,商品詳情是items數(shù)組,點擊分類頁面的商品,路由跳轉(zhuǎn)到詳情頁面,路由參數(shù)是商品在items中的序號。

但是問題是只有第一次點擊商品i的時候可以正常加載items[i]的數(shù)據(jù)到html中,退出后點擊商品j,發(fā)現(xiàn)加載的還是商品i的信息,只有刷新后才會更新成商品j的信息。

部分代碼:

? ? ? ? <shopPanel
? ? ? ? ? ? :key = "nums"
? ? ? ? ? ? :goodname="item.text"
? ? ? ? ? ? :tag="item.tag"
? ? ? ? ? ? :sale="item.sale"
? ? ? ? ? ? :price="item.price"
? ? ? ? ? ? :ori="item.ori_price"
? ? ? ? >
? ? ? ? </shopPanel>

和computed定義的,注意這里定義的數(shù)據(jù)item,是不能夠修改的,想修改只能用set來修改。

我這里測試時發(fā)現(xiàn)明明item關(guān)聯(lián)的兩個屬性this.focus和this.idx改變了,那為什么item沒有改變呢?

而且是刷新后就能改變。

? ? ? ? computed: mapState({
? ? ? ? ? ? items:'items', //商品詳情信息
? ? ? ? ? ? item(){
? ? ? ? ? ? ? ? console.log(this.focus+" "+this.idx);
? ? ? ? ? ? ? ? return this.items[this.focus].children[this.idx]
? ? ? ? ? ? }
? ? ? ? }),

最后的原因竟然是定義路由的時候選擇了keepalive,頁面不會銷毀,改成false就行。

? ? ? ? path: '/item/item01',
? ? ? ? name:'itemdetail',
? ? ? ? meta: {
? ? ? ? ? ? title: '商品1',
? ? ? ? ? ? keepAlive: false,
? ? ? ? ? ? showTab: false
? ? ? ? },
? ? ? ? component: (resolve) => require(['../page/itemdetail/item01'], resolve),

vue computed依賴收集與更新原理

今天面了家小公司,上來直接問 computed 底層原理,面試官是這樣問的,data 中定義了 a 和 b 變量。computed 里面定義了 c 屬性,c 的結(jié)果依賴與 a 和 b,模板中使用了變量 c。假設(shè)改變了 a,請問底層是如何收集依賴,如何觸發(fā)更新的?

<div>{{ c }}</div>
data(){
?? ?return {
?? ??? ?a: 'foo',
?? ??? ?b: 'bar'
?? ?}
},
computed: {
?? ?c() {?
?? ??? ?return this.a + ' - ' + this.b;
?? ? }
},
mounted(){
?? ?setTimeout(() => { this.a = 'FOO' }, 1000)
}

頁面效果:先顯示了 foo - bar,一秒之后顯示 FOO - bar

這里查源碼后,對computed原理簡述如下

1.initState 函數(shù)中初始化了 initComputed

export function initState (vm: Component) {
? vm._watchers = []
? const opts = vm.$options
? if (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)
? }
}

2.initComputed 函數(shù)中遍歷 computed 中每一個屬性,并且 new Watcher(computed watcher),可以看到傳入 Watcher 構(gòu)造函數(shù)的 cb 是 noop,它是一個空函數(shù)。并且 defineComputed

function initComputed (vm: Component, computed: Object) {
? // $flow-disable-line
? const watchers = vm._computedWatchers = Object.create(null)
? // computed properties are just getters during SSR
? const isSSR = isServerRendering()

? for (const key in computed) {
? ? const userDef = computed[key]
? ? const getter = typeof userDef === 'function' ? userDef : userDef.get
? ? if (process.env.NODE_ENV !== 'production' && getter == null) {
? ? ? warn(
? ? ? ? `Getter is missing for computed property "${key}".`,
? ? ? ? vm
? ? ? )
? ? }

? ? if (!isSSR) {
? ? ? // create internal watcher for the computed property.
? ? ? watchers[key] = new Watcher(
? ? ? ? vm,
? ? ? ? getter || noop,
? ? ? ? noop,
? ? ? ? computedWatcherOptions
? ? ? )
? ? }

? ? // component-defined computed properties are already defined on the
? ? // component prototype. We only need to define computed properties defined
? ? // at instantiation here.
? ? if (!(key in vm)) {
? ? ? defineComputed(vm, key, userDef)
? ? } else if (process.env.NODE_ENV !== 'production') {
? ? ? if (key in vm.$data) {
? ? ? ? warn(`The computed property "${key}" is already defined in data.`, vm)
? ? ? } else if (vm.$options.props && key in vm.$options.props) {
? ? ? ? warn(`The computed property "${key}" is already defined as a prop.`, vm)
? ? ? } else if (vm.$options.methods && key in vm.$options.methods) {
? ? ? ? warn(`The computed property "${key}" is already defined as a method.`, vm)
? ? ? }
? ? }
? }
}

3.defineComputed 中使用了 Object.defineProperty 對屬性進行劫持,獲取是返回對應的 getter 即 createComputedGetter

export function defineComputed (
? target: any,
? key: string,
? userDef: Object | Function
) {
? const shouldCache = !isServerRendering()
? if (typeof userDef === 'function') {
? ? sharedPropertyDefinition.get = shouldCache
? ? ? ? createComputedGetter(key)
? ? ? : createGetterInvoker(userDef)
? ? sharedPropertyDefinition.set = noop
? } else {
? ? sharedPropertyDefinition.get = userDef.get
? ? ? ? shouldCache && userDef.cache !== false
? ? ? ? ? createComputedGetter(key)
? ? ? ? : createGetterInvoker(userDef.get)
? ? ? : noop
? ? sharedPropertyDefinition.set = userDef.set || noop
? }
? if (process.env.NODE_ENV !== 'production' &&
? ? ? sharedPropertyDefinition.set === noop) {
? ? sharedPropertyDefinition.set = function () {
? ? ? warn(
? ? ? ? `Computed property "${key}" was assigned to but it has no setter.`,
? ? ? ? this
? ? ? )
? ? }
? }
? Object.defineProperty(target, key, sharedPropertyDefinition)
}

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

看到這里,我們大致可以理解,Vue 組件在初始化時,initState -> initComputed -> new Watcher() 計算watcher,傳入的 callback 是 computer 屬性的 getter,由于 computed 是 lazy: true watcher,所以 new Watcher 時并不會立即執(zhí)行 watcher 實例上的 get(), 而是在 defineComputed 函數(shù)里面調(diào)用 createComputedGetter 函數(shù),在 createComputedGetter 函數(shù)執(zhí)行了 watcher.evaluate() 進而執(zhí)行了 watcher.get().

執(zhí)行 watcher.get() 首先 pushTarget(this),將 Dep.target 賦值為當前的 computed watcher,然后執(zhí)行 this.getter也就是執(zhí)行 computer 屬性配置的 getter,執(zhí)行g(shù)etter 就會訪問所依賴的每一個值,就會被 Object.defineProperty 劫持到進入 get ,執(zhí)行 dep.depend() , 會為每一個屬性對應的 dep 實例添加一個 computed watcher,同時這個 computed watcher 也會保存對應的 dep。

說了這么多都在講 computed watcher,那修改 this.a 頁面為什么會發(fā)生更新呢?

答案:因為 this.a 的依賴中不僅有 computed watcher 還有一個 render watcher

原因:

$mount 是會執(zhí)行 mountComponent,會創(chuàng)建一個 render watcher,它會立即執(zhí)行 cb(目前 Dep.target 是 render watcher),調(diào)用 render 函數(shù)在底層編譯模板,最后訪問屬性計算屬性 c,訪問計算屬性 c 就必定會訪問 a,當訪問 a 時會觸發(fā) defineComputed 中的 Object.defineProperty 進而劫持調(diào)用 createComputedGetter,進而調(diào)用 watcher.depend(),這個 watcher 是 computed watcher

function createComputedGetter (key) {
? return function computedGetter () {
? ? const watcher = this._computedWatchers && this._computedWatchers[key]
? ? if (watcher) {
? ? ? if (watcher.dirty) {
? ? ? ? watcher.evaluate()
? ? ? }
? ? ? if (Dep.target) {
? ? ? ? watcher.depend()
? ? ? }
? ? ? return watcher.value
? ? }
? }
}
// Watcher.js
depend () {
? let i = this.deps.length
? while (i--) {
? ? this.deps[i].depend()
? }
}

調(diào)用 watcher.depend() , this 指的是 computed watcher,會將 computed watcher 里面的 deps 保存在所有依賴調(diào)用 deps[i].depend(),進而調(diào)用 Dep 類中的 Dep.target.addDep(this),使得 render watcher 中保存了當前的 dep,dep 中同時保存了 render watcher。

dep 中同時保存了 render watcher。就可以看出,示例中的屬性 a 的 dep 中也會保存 render watcher,所以 a 屬性的 dep 中有兩個 watcher: [computedWatcher, renderWatcher]

所以,修改 a 屬性的值,最后 notify 會清空這個 保存 watcher 的隊列,進行頁面更新!Okay! 

總結(jié)

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Vue中動態(tài)綁定Ref的兩種方式總結(jié)

    Vue中動態(tài)綁定Ref的兩種方式總結(jié)

    Vue3中的ref是一種創(chuàng)建響應式引用的方式,它在Vue生態(tài)系統(tǒng)中扮演著重要角色,下面這篇文章主要給大家介紹了關(guān)于Vue中動態(tài)綁定Ref的兩種方式,需要的朋友可以參考下
    2024-09-09
  • Vue Getters和mapGetters的原理及使用示例詳解

    Vue Getters和mapGetters的原理及使用示例詳解

    Vuex的核心概念包括state、mutations、actions、getters和modules,今天,我們要深入探討其中一個關(guān)鍵部分:getters,以及它的相關(guān)輔助函數(shù)mapGetters,感興趣的朋友跟隨小編一起看看吧
    2024-08-08
  • vue.js動態(tài)設(shè)置VueComponent高度遇到的問題及解決

    vue.js動態(tài)設(shè)置VueComponent高度遇到的問題及解決

    這篇文章主要介紹了vue.js動態(tài)設(shè)置VueComponent高度遇到的問題及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • 解決vue axios的封裝 請求狀態(tài)的錯誤提示問題

    解決vue axios的封裝 請求狀態(tài)的錯誤提示問題

    今天小編就為大家分享一篇解決vue axios的封裝 請求狀態(tài)的錯誤提示問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-09-09
  • vue element-ui里的table中表頭與表格出現(xiàn)錯位的解決

    vue element-ui里的table中表頭與表格出現(xiàn)錯位的解決

    這篇文章主要介紹了vue element-ui里的table中表頭與表格出現(xiàn)錯位的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • Vue中的組件詳談

    Vue中的組件詳談

    這篇文章主要介紹了Vue的組件,本文通過實例代碼給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-10-10
  • vue兩組件間值傳遞 $router.push實現(xiàn)方法

    vue兩組件間值傳遞 $router.push實現(xiàn)方法

    兩組件間傳值,可能包含多種情況,這篇文章主要介紹了vue兩組件間值傳遞 $router.push實現(xiàn)方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-05-05
  • Vue3 Ref獲取真實DOM學習實戰(zhàn)

    Vue3 Ref獲取真實DOM學習實戰(zhàn)

    這篇文章主要為大家介紹了Vue3 Ref獲取真實DOM學習實戰(zhàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-06-06
  • VUE 3D輪播圖封裝實現(xiàn)方法

    VUE 3D輪播圖封裝實現(xiàn)方法

    這篇文章主要為大家詳細介紹了VUE 3D輪播圖封裝實現(xiàn)方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-07-07
  • vue中l(wèi)et that=this的作用及說明

    vue中l(wèi)et that=this的作用及說明

    這篇文章主要介紹了vue中l(wèi)et that=this的作用及說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-10-10

最新評論