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

vue3手動刪除keepAlive緩存的方法

 更新時間:2024年03月21日 08:24:37   作者:yanessa_yu  
當我們未設置keepAlive的最大緩存數(shù)時,當緩存組件太多,會導致內存溢出,本文給大家介紹了vue3手動刪除keepAlive緩存的方法,文中通過代碼示例介紹的非常詳細,需要的朋友可以參考下

keepAlive的最大緩存數(shù)是無限大

當我們未設置keepAlive的最大緩存數(shù)時,當緩存組件太多,會導致內存溢出。

keepAlive最大緩存數(shù)測試實踐

  • 如下腳本,給組件設置keepAlive緩存,并將組件的key設置為$route.path
 <router-view v-slot="{ Component }">
    <keep-alive >
      <component :is="Component" :key="$route.path"/>
    </keep-alive>
  </router-view>
  • 如下腳本,設置一個動態(tài)路由,不同id共用同一個組件
{
      path: '/el/cascader/:id',
      name: 'ElCascaderDemo2',
      component: () => import('../views/ElCascaderDemo.vue')
    },
  • 如下腳本, 點擊每一行,可以不斷的新增緩存組件
<script setup lang="ts">
 import { useRouter } from 'vue-router'
 const router = useRouter()
  const go = (id: number) => {
    router.push({
      path: '/el/cascader/' + id
    })
  }
</script>

<template>
  <main>
    <div v-for="i in 10000" @click="go(i)" class="item">
      {{  i  }}
    </div>
  </main>
</template>
  • 下面腳本是keepAlive組件中的源碼,在內部打斷點,查看當前cache中緩存的組件數(shù)是多少。
const cacheSubtree = () => {
      if (pendingCacheKey != null) {
        cache.set(pendingCacheKey, getInnerChild(instance.subTree));
      }
    };
    onMounted(cacheSubtree);
    onUpdated(cacheSubtree);
  • 如下圖,當cache中緩存12個組件時,內存已經達到了2G,

  • 如下圖,在繼續(xù)加壓后,內存達到4019MB時,頁面崩潰。

故在使用keepAlive緩存組件,一定要設置它的最大緩存數(shù)。

設置keepAlive最大緩存數(shù)

<router-view v-slot="{ Component }">
    <keep-alive :max="10">
      <component :is="Component" :key="$route.path"/>
    </keep-alive>
  </router-view>

設置最大緩存數(shù)等于10以后,keepAlive組件內緩存變量cache的size<=9,內存位置在1900MB。

實現(xiàn)手動刪除緩存組件

實現(xiàn)手動刪除緩存組件的方式是:動態(tài)增刪keepAlive組件的exclude屬性。exclude屬性的值可以是一個組件名稱組成的數(shù)組。在 3.2.34 或以上的版本中,使用 <script setup> 的單文件組件會自動根據(jù)文件名生成對應的 name 選項,無需再手動聲明。但目前組件的key等于route.path,/el/cascader/1/el/cascader/2會緩存兩份,手動刪除這類組件,需要給它們各自一個名稱,而不是都用它們指向的那一個組件的名稱。

第一步:封裝動態(tài)組件component的is屬性的賦值,使用route.path作為組件的名稱。

 <router-view v-slot="{ Component }">
    <keep-alive :max="10">
      <component :is="formatComponentInstance(Component, $route?.path)" :key="$route.path"/>
    </keep-alive>
  </router-view>
  
  
let wrapperMap = new Map()
const formatComponentInstance = (component : Component, path:string ) => {
  let wrapper
  if (wrapperMap.has(path)) {
    wrapper = wrapperMap.get(path)
  } else {
    wrapper = {
      name: path,
      render(){
        return h(component) // h的第一個參數(shù)可以是字符串,也可以是一個組件定義;h返回的是一個虛擬dom
      }
    }
    wrapperMap.set(path, wrapper)
  }
  return h(wrapper)
}

第二步:實現(xiàn)一個簡單內頁簽,內頁簽關閉時清除組件緩存

<template>
    <el-tag
      v-for="item in editableTabs"
      :key="item.key"
      closable
      :disable-transitions="false"
      @click="tabChange(item.key)"
      @close="handleTabsEdit(item.key, 'remove', undefined)"
      :type="editableKey === item.key ? 'primary':'info'"
    >
      {{ item.title }}
    </el-tag>
  </template>
  <script lang="ts" setup>
  import { ref, watch } from 'vue'
  import type { Ref } from 'vue'
  import { ElTag} from 'element-plus'
  import { useRoute, useRouter} from 'vue-router'
  const route = useRoute()
  const router = useRouter()
  import { useKeepAlive } from '../stores/index'

  let tabIndex = 1
  const editableKey = ref('')
  const editableTabs : Ref<Array<{[key: string]: any}>> = ref([])
  
  const visitedRoute: String [] = []
  watch(() => route.path, (val) => {
    if (visitedRoute.indexOf(val) === -1) {
        visitedRoute.push(val)
        handleTabsEdit(undefined, 'add', val)
    } else {
      editableKey.value = editableTabs.value.filter((tab) => tab.title === val)[0].key
    }
  })
  
  const handleTabsEdit = (
    targetKey: string | undefined,
    action: 'remove' | 'add',
    newTabTitle: string | undefined
  ) => { 
    if (action === 'add') {
      const newTabName = `${++tabIndex}`
      editableTabs.value.push({
        title: newTabTitle,
        key: newTabName,
      })
      editableKey.value = newTabName
    } else if (action === 'remove') {
      const tabs = editableTabs.value
      let activeKey = editableKey.value
      if (activeKey === targetKey) {
        tabs.forEach((tab, index) => {
          if (tab.key === targetKey) {
            //  同步刪除visitedRoute數(shù)組
            let includeIndex = visitedRoute.indexOf(tab.title)
            visitedRoute.splice(includeIndex, 1)
            //    重置active tab
            const nextTab = tabs[index + 1] || tabs[index - 1]
            if (nextTab) {
              activeKey = nextTab.name
              router.push({
                path: nextTab.title
              })
            }
            // /頁簽關閉時,重置store中的exclude數(shù)組,如['/el/cascader/2']
            const keepAliveStore = useKeepAlive()
              let exclude: string[] = [tab.title]
              keepAliveStore.setExclude(exclude)
          }
        })
      }
  
      editableKey.value = activeKey
      editableTabs.value = tabs.filter((tab) => tab.key !== targetKey)
    }
  }

  const tabChange  = (activeKey: string) => {
    let path = editableTabs.value.filter((tab) => tab.key === activeKey)[0].title
    router.push({
        path
    })
  }
  </script>
  
  

const keepAliveStore = useKeepAlive()
const excludes = computed(() => {
  return keepAliveStore.exclude
})

<router-view v-slot="{ Component }">
    <keep-alive :max="10" :exclude="excludes">
      <component :is="formatComponentInstance(Component, $route?.path)" :key="$route.path"/>
    </keep-alive>
  </router-view>

在調試中出現(xiàn)以下報錯:

Uncaught (in promise) TypeError: parentComponent.ctx.deactivate is not a function 報錯的原因是因為我將上面的封裝簡化為以下腳本, 導致同一個path兩次產生的組件vnode的type不一樣。為什么要簡化呢, 因為考慮到wrapperMap會有一定的內存消耗。

const formatComponentInstance = (component : Component, path:string ) => {
    let wrapper = {
      name: path,
      render(){
        return h(component) // h的第一個參數(shù)可以是字符串,也可以是一個組件定義;h返回的是一個虛擬dom
      }
    }
    return h(wrapper)
 }

在vue源碼中的isSameVNodeType中的n1.type === n2.type的判斷中, 組件轉化的vnode的type是一個對象,對于相同的route.path, 每次通過上面的封裝腳本產生新的組件實例,會導致每次產生的vnode的type對象不是同一個對象,導致n1.type不等于n2.type, isSameVNodeType返回false,會卸載n1,卸載時就產生了上面的報錯。

function isSameVNodeType(n1, n2) {
  if (n2.shapeFlag & 6 && hmrDirtyComponents.has(n2.type)) {
    n1.shapeFlag &= ~256;
    n2.shapeFlag &= ~512;
    return false;
  }
  return n1.type === n2.type && n1.key === n2.key;
}

以上就是vue3手動刪除keepAlive緩存的方法的詳細內容,更多關于vue3刪除keepAlive緩存的資料請關注腳本之家其它相關文章!

相關文章

  • Vue實現(xiàn)路由跳轉的3種方式超詳細分解

    Vue實現(xiàn)路由跳轉的3種方式超詳細分解

    Vue.js是一款流行的前端JavaScript框架,它提供了多種方式來實現(xiàn)路由跳轉,下面這篇文章主要給大家介紹了關于Vue實現(xiàn)路由跳轉的3種方式,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2023-12-12
  • vue離開當前頁面觸發(fā)的函數(shù)代碼

    vue離開當前頁面觸發(fā)的函數(shù)代碼

    這篇文章主要介紹了vue離開當前頁面觸發(fā)的函數(shù)代碼,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-09-09
  • Vue 實現(xiàn)從小到大的橫向滑動效果詳解

    Vue 實現(xiàn)從小到大的橫向滑動效果詳解

    這篇文章主要介紹了Vue 實現(xiàn)從小到大的橫向滑動效果,結合實例形式詳細分析了vue.js橫向漸變滑動效果的實現(xiàn)步驟、相關操作技巧與注意事項,需要的朋友可以參考下
    2019-10-10
  • vue3 獲取元素高度不準的問題

    vue3 獲取元素高度不準的問題

    這篇文章主要介紹了vue3 獲取元素高度不準的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • Vuex mutitons和actions初使用詳解

    Vuex mutitons和actions初使用詳解

    這篇文章主要介紹了Vuex mutitons和actions初使用詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-03-03
  • vue3使用echarts并封裝echarts組件方式

    vue3使用echarts并封裝echarts組件方式

    這篇文章主要介紹了vue3使用echarts并封裝echarts組件方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-10-10
  • vue+Element-ui前端實現(xiàn)分頁效果

    vue+Element-ui前端實現(xiàn)分頁效果

    這篇文章主要為大家詳細介紹了vue+Element-ui前端實現(xiàn)分頁效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-11-11
  • vue自定義指令實現(xiàn)元素滑動移動端適配及邊界處理

    vue自定義指令實現(xiàn)元素滑動移動端適配及邊界處理

    這篇文章主要為大家介紹了vue自定義指令實現(xiàn)元素滑動移動端適配及邊界處理詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-09-09
  • 詳解vue3中如何使用youtube-player

    詳解vue3中如何使用youtube-player

    這篇文章主要為大家介紹了詳解vue3中如何使用youtube-player示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-09-09
  • 詳解Vue基于vue-quill-editor富文本編輯器使用心得

    詳解Vue基于vue-quill-editor富文本編輯器使用心得

    這篇文章主要介紹了Vue基于vue-quill-editor富文本編輯器使用心得,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-01-01

最新評論