最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

vue定義在computed的變量無(wú)法更新問(wèn)題及解決

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

vue定義在computed的變量無(wú)法更新

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

但是問(wèn)題是只有第一次點(diǎn)擊商品i的時(shí)候可以正常加載items[i]的數(shù)據(jù)到html中,退出后點(diǎn)擊商品j,發(fā)現(xiàn)加載的還是商品i的信息,只有刷新后才會(huì)更新成商品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來(lái)修改。

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

而且是刷新后就能改變。

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

最后的原因竟然是定義路由的時(shí)候選擇了keepalive,頁(yè)面不會(huì)銷毀,改成false就行。

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

vue computed依賴收集與更新原理

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

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

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

這里查源碼后,對(duì)computed原理簡(jiǎn)述如下

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 中每一個(gè)屬性,并且 new Watcher(computed watcher),可以看到傳入 Watcher 構(gòu)造函數(shù)的 cb 是 noop,它是一個(gè)空函數(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 對(duì)屬性進(jìn)行劫持,獲取是返回對(duì)應(yīng)的 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 組件在初始化時(shí),initState -> initComputed -> new Watcher() 計(jì)算watcher,傳入的 callback 是 computer 屬性的 getter,由于 computed 是 lazy: true watcher,所以 new Watcher 時(shí)并不會(huì)立即執(zhí)行 watcher 實(shí)例上的 get(), 而是在 defineComputed 函數(shù)里面調(diào)用 createComputedGetter 函數(shù),在 createComputedGetter 函數(shù)執(zhí)行了 watcher.evaluate() 進(jìn)而執(zhí)行了 watcher.get().

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

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

答案:因?yàn)?this.a 的依賴中不僅有 computed watcher 還有一個(gè) render watcher

原因:

$mount 是會(huì)執(zhí)行 mountComponent,會(huì)創(chuàng)建一個(gè) render watcher,它會(huì)立即執(zhí)行 cb(目前 Dep.target 是 render watcher),調(diào)用 render 函數(shù)在底層編譯模板,最后訪問(wèn)屬性計(jì)算屬性 c,訪問(wèn)計(jì)算屬性 c 就必定會(huì)訪問(wèn) a,當(dāng)訪問(wèn) a 時(shí)會(huì)觸發(fā) defineComputed 中的 Object.defineProperty 進(jìn)而劫持調(diào)用 createComputedGetter,進(jìn)而調(diào)用 watcher.depend(),這個(gè) 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,會(huì)將 computed watcher 里面的 deps 保存在所有依賴調(diào)用 deps[i].depend(),進(jìn)而調(diào)用 Dep 類中的 Dep.target.addDep(this),使得 render watcher 中保存了當(dāng)前的 dep,dep 中同時(shí)保存了 render watcher。

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

所以,修改 a 屬性的值,最后 notify 會(huì)清空這個(gè) 保存 watcher 的隊(duì)列,進(jìn)行頁(yè)面更新!Okay! 

總結(jié)

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

相關(guān)文章

  • 關(guān)于element-ui?select?下拉框位置錯(cuò)亂問(wèn)題解決

    關(guān)于element-ui?select?下拉框位置錯(cuò)亂問(wèn)題解決

    這篇文章主要介紹了關(guān)于element-ui?select?下拉框位置錯(cuò)亂問(wèn)題解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-09-09
  • elementui導(dǎo)出數(shù)據(jù)為xlsx、excel表格

    elementui導(dǎo)出數(shù)據(jù)為xlsx、excel表格

    本文主要介紹了elementui導(dǎo)出數(shù)據(jù)為xlsx、excel表格,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • vue3無(wú)法使用jsx的問(wèn)題及解決

    vue3無(wú)法使用jsx的問(wèn)題及解決

    這篇文章主要介紹了vue3無(wú)法使用jsx的問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-09-09
  • vue?注釋template中組件的屬性說(shuō)明

    vue?注釋template中組件的屬性說(shuō)明

    這篇文章主要介紹了vue?注釋template中組件的屬性說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-04-04
  • vue中動(dòng)態(tài)設(shè)置meta標(biāo)簽和title標(biāo)簽的方法

    vue中動(dòng)態(tài)設(shè)置meta標(biāo)簽和title標(biāo)簽的方法

    這篇文章主要介紹了vue中動(dòng)態(tài)設(shè)置meta標(biāo)簽和title標(biāo)簽的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-07-07
  • 如何使用vuejs實(shí)現(xiàn)更好的Form validation?

    如何使用vuejs實(shí)現(xiàn)更好的Form validation?

    如何使用vuejs實(shí)現(xiàn)更好的Form validation?這篇文章主要介紹了vue-form插件的使用方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-04-04
  • VUE實(shí)時(shí)監(jiān)聽(tīng)元素距離頂部高度的操作

    VUE實(shí)時(shí)監(jiān)聽(tīng)元素距離頂部高度的操作

    這篇文章主要介紹了VUE實(shí)時(shí)監(jiān)聽(tīng)元素距離頂部高度的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-07-07
  • vue-Router安裝過(guò)程及原理詳細(xì)

    vue-Router安裝過(guò)程及原理詳細(xì)

    路由是網(wǎng)絡(luò)工程里面的專業(yè)術(shù)語(yǔ),就是通過(guò)互聯(lián)把信息從源地址傳輸?shù)侥康牡刂返幕顒?dòng)。本質(zhì)上就是一種對(duì)應(yīng)關(guān)系。分為前端路由和后端路由。小編將再下面文章為大家做詳細(xì)介紹,感興趣的小伙伴請(qǐng)和小編一起來(lái)學(xué)習(xí)吧
    2021-09-09
  • vue中使用$http.post請(qǐng)求傳參的錯(cuò)誤及解決

    vue中使用$http.post請(qǐng)求傳參的錯(cuò)誤及解決

    這篇文章主要介紹了vue中使用$http.post請(qǐng)求傳參的錯(cuò)誤及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-04-04
  • vue實(shí)現(xiàn)圖書管理demo詳解

    vue實(shí)現(xiàn)圖書管理demo詳解

    這篇文章主要介紹了vue實(shí)現(xiàn)圖書管理,分享了圖書管理demo用的知識(shí)點(diǎn),以及遇到問(wèn)題的總結(jié),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-10-10

最新評(píng)論

饶平县| 方正县| 达拉特旗| 阿荣旗| 蓬莱市| 五家渠市| 横峰县| 资阳市| 隆尧县| 都安| 阳原县| 平乡县| 台中县| 玛沁县| 大姚县| 耿马| 永平县| 拜城县| 桐梓县| 西平县| 同江市| 天津市| 吉首市| 北票市| 聂拉木县| 共和县| 大方县| 文山县| 荆门市| 和林格尔县| 永城市| 抚顺县| 乐业县| 广灵县| 会泽县| 扎赉特旗| 绿春县| 临西县| 萍乡市| 囊谦县| 霍山县|