keep-alive緩存路由在動(dòng)態(tài)路徑參數(shù)中出現(xiàn)的問題(一)

公司后臺(tái)管理系統(tǒng),產(chǎn)品經(jīng)理希望做一個(gè)tab欄,可以切換不同的頁(yè)面,類似于很早之前通過iframe的方式進(jìn)行各個(gè)page之間的切換。這邊直接使用的keep-alive
layout組件如下

// @/layouts/BasicLayout.vue
<template>
  <keep-alive>
    <router-view />
  </keep-alive>
</template>

<script>

export default {
  name: 'BasicLayout'
}
</script>

如下路由配置

// @/router/index.js
const routes = [{
  name: 'index',
  path: '/keep-alive',
  component: BasicLayout,
  children: [
    {
      path: 'one',
      name: 'demoOne',
      component: DemoOne
    },
    {
      path: 'two/:id',
      name: 'demoTwo',
      component: DemoTwo
    },
    {
      path: 'three/:id',
      name: 'DemoThree',
      component: DemoThree
    }
  ]
}]

然后是demo-one

// demo-one.vue
<template>
  <div class="demo">
    <div>This is demo one</div>
  </div>
</template>

然后是demo-two

// demo-two.vue
<template>
  <div class="demo">
    <h4>DEMO-TWO</h4>
    <div>這是ID:{{id}}</div>
    <div>
      <input type="text" :placeholder="placeholder">
    </div>
  </div>
</template>

<script>
export default {
  data () {
    const { id } = this.$route.params
    return {
      id,
      placeholder: `請(qǐng)輸入ID:${id}對(duì)應(yīng)的名字`
    }
  }
}
</script>

但是如果遇到需要使用動(dòng)態(tài)路徑參數(shù)的話,就會(huì)出現(xiàn)問題

  1. demo-two中的id不會(huì)隨著路徑中的id的改變而改變
  2. 在demo-two/1頁(yè)面中的input框輸入值后,在demo-two/2,demo-two/3,demo-two/4,demo-two/5中同樣會(huì)顯示這個(gè)值。


    案例圖片

解決方案1:使用路由組件傳參

// @/router/index
// ...
    {
      path: 'two/:id',
      name: 'demoTwo',
      component: DemoTwo,
      props: true
    },
// ...
// @/pages/demo-two.vue
export default {
  props: {
    id: {
      type: String,
      required: true
    }
  },
  computed: {
    placeholder () {
      return `請(qǐng)輸入ID:${this.id}對(duì)應(yīng)的名字`
    }
  }
}

修改過后問題一得到了解決,但是問題二依然存在


修改過后問題一得到了解決,但是問題二依然存在

查看keep-alive源代碼

// /Users/zhaoxuetong/github/vue/src/core/components/keep-alive.js
    const key: ?string = vnode.key == null
      // same constructor may get registered as different local components
      // so cid alone is not enough (#3269)
      ? componentOptions.Ctor.cid + (componentOptions.tag ? `::${componentOptions.tag}` : '')
      : vnode.key

    if (cache[key]) {
      vnode.componentInstance = cache[key].componentInstance
      // make current key freshest
      remove(keys, key)
      keys.push(key)
    } else {
      cache[key] = vnode
      keys.push(key)
      // prune oldest entry
      if (this.max && keys.length > parseInt(this.max)) {
        pruneCacheEntry(cache, keys[0], keys, this._vnode)
      }
    }

keep-alive緩存子組件的使用的健名(key)的邏輯如下:
如果vnode上有key,則使用key,不過不存在key則使用componentOptions.Ctor.cid + (componentOptions.tag ? ::${componentOptions.tag} : '')。由于

  1. 沒有在組件上使用key。
  2. router-view這一層,componentOptions.tag也沒有值
  3. 所以最終獲得的key就是vnode.componentOptions.Ctor.cid
    由同一個(gè)組件所渲染的實(shí)例的cid都是一樣的。
    所以其實(shí)根據(jù)demo-two渲染出來(lái)的5個(gè)組件的cid都是一樣的,那么keep-alive其實(shí)緩存的就是同一個(gè)vnode. componentInstance。所以看到只要在一個(gè)路徑下輸入了input的內(nèi)容,其余四個(gè)都會(huì)同時(shí)改變。

那么我們?cè)趘ue-route上加上key,那么就可是實(shí)現(xiàn)我們想要的效果。

// @/layouts/BasicLayout.vue
<template>
  <keep-alive>
    <router-view :key="$route.fullPath" />
  </keep-alive>
</template>

<script>
export default {
  name: 'BasicLayout'
}
</script>
增加key之后的效果圖.gif

打印出來(lái)的keep-alive的cache的緩存

keep-alive緩存路由在動(dòng)態(tài)路徑參數(shù)中出現(xiàn)的問題(二)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容