目錄
- 前言
- 1. 基本知識
- 2. Demo
- 2.1 基本
- 2.2 拓展
- 2.3 終極
- 3. 實戰
前言
🤟 找工作,來萬碼優才:👉 #小程序://萬碼優才/r6rqmzDaXpYkJZF
基本知識推薦閱讀:KeepAlive知識點
從實戰中學習,源自實戰中vue路由的緩存設置
<router-view v-if="routerAlive"><template #default="{ Component, route }"><keep-alive :include="getCaches"><component :is="Component" :key="route.fullPath" /></keep-alive></template>
</router-view>
截圖如下:
1. 基本知識
<KeepAlive>
內置組件,用于緩存動態組件或路由組件,以提高性能
可以保留組件的狀態,避免重復渲染和生命周期鉤子的重新調用
KeepAlive 作用
- 緩存組件,提高性能,避免組件反復銷毀和創建
- 保留組件的狀態,例如表單填寫內容、滾動位置等
- 控制緩存,可以指定哪些組件需要被緩存,哪些不需要
KeepAlive 適用場景
- 需要緩存的 多頁面表單
- 列表詳情頁切換 時,保留列表的滾動位置
- 復雜組件切換時,避免重新渲染帶來的性能開銷
功能 | 說明 |
---|---|
KeepAlive | 用于緩存組件,提高性能 |
include | 指定要緩存的組件(支持字符串或數組) |
exclude | 指定不緩存的組件 |
max | 限制最大緩存組件數量 |
activated() | 組件被激活時觸發 |
deactivated() | 組件被緩存時觸發 |
include 和 exclude
可以通過 include 和 exclude 來決定哪些組件需要被緩存,哪些不需要
<keep-alive include="ComponentA"><component :is="currentComponent"></component>
</keep-alive>
只有 ComponentA 會被緩存,而 ComponentB 不會
或者:
<keep-alive :include="['ComponentA', 'ComponentC']"><component :is="currentComponent"></component>
</keep-alive>
只有 ComponentA 和 ComponentC 會被緩存
如果需要排除某個組件:
<keep-alive exclude="ComponentB"><component :is="currentComponent"></component>
</keep-alive>
ComponentB 不會被緩存,而其他組件都會被緩存
max —— 設置緩存組件的最大數量
如果緩存的組件較多,可以設置 max 限制最多緩存多少個組件
只緩存最近的兩個組件,超出的組件會被銷毀
<keep-alive :max="2"><component :is="currentComponent"></component>
</keep-alive>
KeepAlive 生命周期鉤子
Vue 提供了兩個專門用于 KeepAlive 組件的生命周期鉤子:
activated()
:組件被激活(切換到緩存中的組件時調用)
deactivated()
:組件被緩存(切換到另一個組件時調用)
<script>
export default {created() {console.log("組件創建");},activated() {console.log("組件被激活");},deactivated() {console.log("組件被緩存");},destroyed() {console.log("組件被銷毀");},
};
</script>
運行效果:
- 組件首次渲染時,created() 會觸發
- 當組件切換回來時,activated() 會觸發,而不會重新執行 created()
- 切換到別的組件時,deactivated() 觸發,而不會執行 destroyed()
- 只有當緩存被清除時,才會執行 destroyed()
2. Demo
2.1 基本
動態組件緩存
<template><div><button @click="currentComponent = 'ComponentA'">切換到A</button><button @click="currentComponent = 'ComponentB'">切換到B</button><keep-alive><component :is="currentComponent"></component></keep-alive></div>
</template><script>
import ComponentA from "./ComponentA.vue";
import ComponentB from "./ComponentB.vue";export default {data() {return {currentComponent: "ComponentA",};},components: {ComponentA,ComponentB,},
};
</script>
組件 A (ComponentA.vue):
<template><div><h3>組件 A</h3><input v-model="text" placeholder="輸入內容會被緩存" /></div>
</template><script>
export default {data() {return {text: "",};},created() {console.log("ComponentA 創建");},destroyed() {console.log("ComponentA 被銷毀");},
};
</script>
組件 B (ComponentB.vue):
<template><div><h3>組件 B</h3></div>
</template><script>
export default {created() {console.log("ComponentB 創建");},destroyed() {console.log("ComponentB 被銷毀");},
};
</script>
一個最明顯的變化就是:
在 ComponentA 中輸入一些文字,然后切換到 ComponentB,再切回來,發現輸入內容還在(ComponentA 沒有被銷毀)
2.2 拓展
KeepAlive 也可以與 Vue Router 結合,緩存路由組件
這樣在 PageA 和 PageB 之間切換時,PageA 不會被銷毀,而是會被緩存
<template><div><router-link to="/pageA">頁面 A</router-link><router-link to="/pageB">頁面 B</router-link><keep-alive><router-view></router-view></keep-alive></div>
</template>
路由配置:
import { createRouter, createWebHistory } from "vue-router";
import PageA from "./PageA.vue";
import PageB from "./PageB.vue";const routes = [{ path: "/pageA", component: PageA },{ path: "/pageB", component: PageB },
];const router = createRouter({history: createWebHistory(),routes,
});export default router;
2.3 終極
這也是實戰中常用的一種方式,從實戰中抽離出基本的Demo,以 Vue 3 + Vue Router 4 + Pinia
裝依賴:npm install vue-router@4 pinia
main.ts(應用入口)
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import { createRouter, createWebHistory } from 'vue-router'
import App from './App.vue'
import Home from './views/Home.vue'
import About from './views/About.vue'
import Profile from './views/Profile.vue'const pinia = createPinia()// 定義路由
const routes = [{ path: '/', component: Home, name: 'Home' },{ path: '/about', component: About, name: 'About' },{ path: '/profile', component: Profile, name: 'Profile' }
]const router = createRouter({history: createWebHistory(),routes
})const app = createApp(App)
app.use(pinia)
app.use(router)
app.mount('#app')
store/tagsView.ts(Pinia 狀態管理 - 維護緩存組件列表)
import { defineStore } from 'pinia'export const useTagsViewStore = defineStore('tagsView', {state: () => ({cachedViews: new Set<string>()}),getters: {getCachedViews(): string[] {return Array.from(this.cachedViews)}},actions: {addCachedView(name: string) {this.cachedViews.add(name)},removeCachedView(name: string) {this.cachedViews.delete(name)},clearCachedViews() {this.cachedViews.clear()}}
})
App.vue(KeepAlive 組件封裝)
<script setup lang="ts">
import { computed, ref, provide, nextTick } from 'vue'
import { useTagsViewStore } from './store/tagsView'
import { RouterView } from 'vue-router'const tagsViewStore = useTagsViewStore()
const getCaches = computed(() => tagsViewStore.getCachedViews)// 無感刷新功能
const routerAlive = ref(true)
const reload = () => {routerAlive.value = falsenextTick(() => (routerAlive.value = true))
}
provide('reload', reload)
</script><template><div><router-view v-if="routerAlive"><template #default="{ Component, route }"><keep-alive :include="getCaches"><component :is="Component" :key="route.fullPath" /></keep-alive></template></router-view></div>
</template>
views/Home.vue
<script setup lang="ts">
import { inject } from 'vue'const reload = inject('reload') as () => void
</script><template><div><h1>Home Page</h1><button @click="reload">刷新當前組件</button></div>
</template>
views/About.vue
<template><div><h1>About Page</h1></div>
</template>
views/Profile.vue
<template><div><h1>Profile Page</h1></div>
</template>
動態路由的常用操作
- 動態添加路由
在 router.ts 中可以動態添加路由:
import router from './router'const newRoute = {path: '/new-page',component: () => import('@/views/NewPage.vue'),name: 'NewPage'
}router.addRoute(newRoute)
-
動態移除路由:
router.removeRoute('NewPage')
-
監聽路由變化
import { useRoute, useRouter } from 'vue-router'
import { watch } from 'vue'const route = useRoute()
const router = useRouter()watch(() => route.fullPath, (newPath) => {console.log('路由發生變化:', newPath)
})
3. 實戰
以ruoyi-vue-pro實戰的Demo進行講解,源碼:芋道源碼/ruoyi-vue-pro
具體KeepAlive,其文件在App.vue中
<router-view v-if="routerAlive"><template #default="{ Component, route }"><keep-alive :include="getCaches"><component :is="Component" :key="route.fullPath" /></keep-alive></template>
</router-view>
通過組件的設置是否路由進行緩存,后續獲取到這個路由信息時,對應判定是否該路由有緩存信息
const getCaches = computed((): string[] => {const caches = tagsViewStore.getCachedViewsconsole.log('當前緩存的組件:', caches) // 打印緩存的組件名稱return caches
})const tagsView = computed(() => appStore.getTagsView)//region 無感刷新
const routerAlive = ref(true)
// 無感刷新,防止出現頁面閃爍白屏
const reload = () => {routerAlive.value = falsenextTick(() => (routerAlive.value = true))
}
// 為組件后代提供刷新方法
provide('reload', reload)
對應的tagsView信息如下:
后續在tsx中進行引用
后續新增路由的時候,其路由地址 要和 defineOptions({ name: 'xxx' })
對應一致