效果图
默认情况下没有 noCache属性 或为false 都会进行缓存 true不缓存


再切回来input内容还在
如果为true


再切回来 input内容没有了
右键删除某一个标签导航时也要删除对应路由缓存
效果
关闭后再打开 input内容被清空
5-1 修改store创建缓存列表
再添加标签导航时,同时也判断该路由要不要缓存,要缓存就根据路由配置的name属性进行缓存(路由组件的name要与路由配置的name一致)再添加到keep-alive inludes的缓存列表中。 (keep-alive内部是根据组件的name进行缓存,我们添加到cachedViews缓存列表的name是从每条路由配置的name取得值,所以路由组件和路由配置中必须要有一致的name属性。)
tagsView module
主要就是添加cachedViews缓存集合,再新增用来添加和删除cachedViews缓存列表actions和muations
state

actions (添加、删除)
mutations
src/store/modules/tagsView.ts
import { Module, ActionTree, MutationTree } from 'vuex'import { RouteRecordRaw, RouteRecordNormalized, RouteRecordName } from 'vue-router'import { IRootState } from '@/store'// 携带fullPathexport interface RouteLocationWithFullPath extends RouteRecordNormalized {fullPath?: string;}export interface ITagsViewState {// 存放当前显示的tags view集合visitedViews: RouteLocationWithFullPath[];// 根据路由name缓存集合cachedViews: RouteRecordName[];}// 定义mutationsconst mutations: MutationTree<ITagsViewState> = {// 添加可显示tags viewADD_VISITED_VIEW(state, view) {// 过滤去重if (state.visitedViews.some(v => v.path === view.path)) return// 没有titles时处理state.visitedViews.push(Object.assign({}, view, {title: view.meta.title || 'tag-name'}))},// 如果路由meta.noCache没有 默认或为false代表进行缓存,为true不缓存// 默认缓存所有路由ADD_CACHED_VIEW(state, view) {// 只有路由有name才可缓存集合keep-alive inludes使用if (state.cachedViews.includes(view.name)) returnif (!view.meta.noCache) {state.cachedViews.push(view.name)}},// 可删除指定的一个viewDEL_VISITED_VIEW(state, view) {const i = state.visitedViews.indexOf(view)if (i > -1) {state.visitedViews.splice(i, 1)}},// 可删除指定的一个view缓存DEL_CACHED_VIEW(state, view) {const index = state.cachedViews.indexOf(view.name)index > -1 && state.cachedViews.splice(index, 1)},// 清空缓存列表DEL_ALL_CACHED_VIEWS(state) {state.cachedViews = []}}// 定义actionsconst actions: ActionTree<ITagsViewState, IRootState> = {// 添加tags viewaddView({ dispatch }, view: RouteRecordRaw) {// 添加tag时也要判断该tag是否需要缓存dispatch('addVisitedView', view)dispatch('addCachedView', view)},// 添加可显示的tags view 添加前commit里需要进行去重过滤addVisitedView({ commit }, view: RouteRecordRaw) {commit('ADD_VISITED_VIEW', view)},// 添加可缓存的标签tagaddCachedView({ commit }, view: RouteRecordRaw) {commit('ADD_CACHED_VIEW', view)},// 删除指定tags view 同时要把它从visitedViews和cachedViews中删除delView({ dispatch }, view: RouteRecordRaw) {return new Promise(resolve => {// 删除对应显示的路由tagdispatch('delVisitedView', view)// 删除对应缓存的路由dispatch('delCachedView', view)resolve(null)})},// 从可显示的集合中 删除tags viewdelVisitedView({ commit }, view: RouteRecordRaw) {commit('DEL_VISITED_VIEW', view)},// 从缓存列表删除指定tag viewdelCachedView({ commit }, view: RouteRecordRaw) {return new Promise(resolve => {commit('DEL_CACHED_VIEW', view)resolve(null)})},// 清空缓存列表delAllCachedViews({ commit }) {commit('DEL_ALL_CACHED_VIEWS')}}const tagsView: Module<ITagsViewState, IRootState> = {namespaced: true,state: {visitedViews: [],cachedViews: []},mutations,actions}export default tagsView
5-2 AppMain中根据store中cachedViews列表进行缓存
之前我们是在AppMian中给了keep-alive的includes空数组,现在换成从store中获取cachedViews缓存列表

src/layout/components/AppMain.vue
<template><div class="app-main"><!-- vue3 路由缓存 https://next.router.vuejs.org/guide/migration/index.html#router-view-keep-alive-and-transition --><router-view v-slot={Component}><transition name="fade-transform" mode="out-in"><keep-alive :include="cachedViews"><component :is="Component" :key="key" /></keep-alive></transition></router-view></div></template><script lang="ts">import { computed, defineComponent } from 'vue'import { useRoute } from 'vue-router'import { useStore } from '@/store'export default defineComponent({name: 'AppMain',setup() {const route = useRoute()const store = useStore()const key = computed(() => route.path)// 缓存路由集合 暂时先是空数组const cachedViews = computed(() => store.state.tagsView.cachedViews)return {key,cachedViews}}})</script><style lang="scss" scoped>.app-main {/* navbar 50px */min-height: calc(100vh - 50px);}.fade-transform-enter-active,.fade-transform-leave-active {transition: all .5s;}.fade-transform-enter-from {opacity: 0;transform: translateX(-30px);}.fade-transform-leave-to {opacity: 0;transform: translateX(30px);}</style>
5-3 修改SizeSelect组件
SizeSelect组件主要用来切换element组件size,由于路由默认会被缓存,会导致动态修改了elemnt组件size不更新,所以需要在修改size后 清空缓存里列表 在刷新当前路由

<template><div><el-dropdown trigger="click" @command="handleSize"><div><svg-icon class-name="size-icon" icon-class="size"></svg-icon></div><template #dropdown><el-dropdown-menu><el-dropdown-itemv-for="item in sizeOptions":key="item.value":command="item.value":disabled="item.value === size">{{ item.label }}</el-dropdown-item></el-dropdown-menu></template></el-dropdown></div></template><script lang="ts">import { Size } from '@/plugins/element'import {defineComponent,ref,getCurrentInstance,ComponentInternalInstance,ComponentPublicInstance,computed} from 'vue'import { useRoute, useRouter } from 'vue-router'import { useStore } from '@/store'import { nextTick } from 'process'export default defineComponent({name: 'SizeSelect',setup() {const store = useStore()const route = useRoute()const router = useRouter()const { proxy } = getCurrentInstance() as ComponentInternalInstance// store中获取sizeconst size = computed(() => store.getters.size)// element size 选项const sizeOptions = ref([{ label: 'Default', value: 'default' },{ label: 'Medium', value: 'medium' },{ label: 'Small', value: 'small' },{ label: 'Mini', value: 'mini' }])// 刷新当前路由const refreshView = () => {// 需要清除路由缓存 否则size配置改变后组件size状态被缓存不更新store.dispatch('tagsView/delAllCachedViews')const { fullPath } = routenextTick(() => {// 跳转到重定向中间页 实现当前路由刷新router.replace({path: '/redirect' + fullPath})})}// command 获取点击按钮的command属性值 作为size值const handleSize = (command: Size) => {// 修改element-plus组件尺寸(proxy as ComponentPublicInstance).$ELEMENT.size = command// 更新storestore.dispatch('app/setSize', command)// 切换size需要刷新路由才能生效refreshView()proxy?.$message.success({type: 'success',message: 'Switch Size Success'})}return {sizeOptions,size,handleSize}}})</script><style lang="scss">.size-icon {font-size: 18px;}</style>
5-3 测试
本节参考源码
https://gitee.com/brolly/vue3-element-admin/commit/cb38b128c2a0b193d4ca42083b11e1c1b1c97870

