ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

5.keep-alive+多标签缓存

5.keep-alive+多标签缓存 一、添加对应store文件放置cacheViews数组需要缓存的页面名称列表、visitedViews数组所有打开的标签页添加tags组件tagsView.tsimport { defineStore } from pinia import { ref } from vue import type { RouteLocationNormalized } from vue-router // 导出 TagView 类型供其他组件使用 export interface TagView extends RouteLocationNormalized { title?: string icon?: string affix?: boolean fullPath: string } export const useTagsView defineStore(tagsView, () { const cacheViews refstring[]([]) const visitedViews refTagView[]([]) // 新增标签页 const addVisitedViews (route: TagView) { const exists visitedViews.value.some(v v.path route.path) if (!exists) { visitedViews.value.push( Object.assign({}, route, { title: route.meta.title }) ) } } // 新增缓存 const addCacheView (name: string) { cacheViews.value.push(name) } // 删除缓存 const removeCache (name: string) { const index cacheViews.value.indexOf(name) if (index -1) { cacheViews.value.splice(index, 1) } } // 关闭标签页 const closeVisitedView (route: TagView) { // 从visitedViews移除 const index visitedViews.value.findIndex(v v.path route.path) if (index -1) { visitedViews.value.splice(index, 1) } if (route.name typeof route.name string) { removeCache(route.name) } } return { cacheViews, visitedViews, addVisitedViews, closeVisitedView, removeCache, addCacheView } })添加标签组件views/layout/components/tag-view/index.vuetemplate div classtagCard TagItem v-foritem in visitedViews :keyitem.path :tagItemitem clickhandleClick(item)/TagItem /div /template script setup langts import { computed, onMounted, watch } from vue import TagItem from ./components/tagItem.vue import { useTagsView, type TagView } from /store/modules/tagsView.ts import { useRouter, useRoute } from vue-router const tagStore useTagsView() const router useRouter() const route useRoute() const visitedViews computed(() { return tagStore.visitedViews }) const routes computed(() { return router.getRoutes() }) onMounted(() { initTags() // 先初始化固定标签 addTags() // 添加标签 }) watch( () route.fullPath, () { addTags() // moveToCurrentTag() } ) const handleClick (tag: TagView) { router.push(tag.fullPath || tag.path) } const filterAffixTags (routes: any[], basePath /) { let tags: TagView[] [] routes.forEach(route { const tagPath basePath / ? route.path : ${basePath}${route.path} if (route.meta.affix) { tags.push({ fullPath: tagPath, path: tagPath, name: route.name, meta: { ...route.meta }, title: route.meta.title || route.name } as TagView) } if (route.children route.children.length) { const childBasePath basePath / ? route.path : ${basePath}${route.path} const tempTags filterAffixTags(route.children, childBasePath) if (tempTags tempTags.length) { tags [...tags, ...tempTags] } } }) return tags } // 辅助函数安全获取路由名称 const getRouteName (route: any): string | undefined { if (!route?.name) return undefined if (typeof route.name string) return route.name if (typeof route.name symbol) return route.name.toString() return undefined } const initTags () { const affixTags filterAffixTags(routes.value) console.log(affixTags,affixTags) for (const tag of affixTags) { if (tag.name) { tagStore.addVisitedViews(tag) } } } const addTags () { tagStore.addVisitedViews(route) const routeName getRouteName(route) if (routeName) { tagStore.addCacheView(routeName) } } /script style langscss scoped .tagCard { display: flex; cursor: pointer; } /styletagItem:template div classtagItem :class{active: isActive} span stylemargin-right: 10px{{ tagItem?.meta.title }}/span CloseOutlined v-ifvisitedViews.length 1 !tagItem.meta.affix click.stopcloseTag(tagItem) / /div /template script setup langts import { useTagsView, type TagView} from /store/modules/tagsView import { computed } from vue import { useRoute, useRouter } from vue-router const tagStore useTagsView() const route useRoute() const router useRouter() const props defineProps{ tagItem: TagView }() const toNextView (visitedViews: TagView[], view: TagView, nextPathIndex: number) { const nextView visitedViews[nextPathIndex] || visitedViews[nextPathIndex - 1] if (nextView) { router.push(nextView.fullPath) } else { // 默认跳转主页 router.push(/) } } const closeTag (tab: TagView) { const nextPathIndex visitedViews.value.findIndex(e { return e.path tab.path }) tagStore.closeVisitedView(tab) // 如果关闭的是当前激活标签则跳转到其他标签 if (props.tagItem.title route.path || props.tagItem.fullPath route.fullPath) { toNextView(visitedViews.value, tab, nextPathIndex) } } const visitedViews computed(() { return tagStore.visitedViews }) const isActive computed(() { return props.tagItem.title route.path || props.tagItem.fullPath route.fullPath }) /script style langscss scoped .tagItem { display: inline-flex; align-items: center; margin: 10px; border: 1px solid #e2e8f0; border-radius: 5px; padding: 0 11px; height: 32px; transition: all 0.3s ease; } .tagItem:hover { // background: #e6f7ff; // border-color: #40a9ff; color: #395ae3; } .tagItem.active { // background: #1890ff; // border-color: #1890ff; color: #395ae3; // box-shadow: 0 2px 8px rgba(24, 144, 255, 0.3); } .tagItem.active span { color: #395ae3; } .tagItem.active .anticon-close { color: #395ae3; } /stylelayout中引入记得keep-alive 要加上:includecacheViewstemplate a-layout a-layout-sider classsiderBar v-model:collapsedcollapsed :triggernull collapsible div classtitleWrap img :srcdefaultSetting.logo/ div classtitle :class{collapsed: settingStore.menuCollapse}{{ defaultSetting.name }}/div /div SiderBar/SiderBar /a-layout-sider a-layout Header/Header TabNav / a-layout-content classmain-content router-view v-slot{ Component, route } transition namefade-transform modeout-in keep-alive :includecacheViews component v-ifComponent :isComponent :keyroute.path / /keep-alive /transition /router-view /a-layout-content /a-layout /a-layout /template script setup langts import { computed } from vue import SiderBar from ./components/siderBar/index.vue import TabNav from ./components/tag-view/index.vue import Header from ./components/header/index.vue import { useSettingStore } from /store/modules/setting.ts import { useTagsView } from /store/modules/tagsView.ts import defaultSetting from /commom/defaultSetting.ts defineOptions({ name: Layout }) const settingStore useSettingStore() const tagsViewStore useTagsView() const collapsed computed(() { return settingStore.menuCollapse }) const cacheViews computed(() { return tagsViewStore.cacheViews }) /script style scoped langscss .siderBar { background-color: #ffffff; color: #000000; font-size: 26px; .titleWrap { display: flex; align-items: center; justify-content: center; overflow: hidden; height: 64px; padding: 0 16px; .title { font-size: 16px; margin-left: 15px; white-space: nowrap; overflow: hidden; max-width: 200px; opacity: 1; transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.3s ease, margin-left 0.3s ease; } } } .title.collapsed { opacity: 0; margin-left: 0; max-width: 0; } /style二、渲染逻辑1.初始的时候1初始的时候添加当前路由进cacheViews和visitedViewsonMounted(() { initTags() // 先初始化固定标签 addTags() // 添加标签 })watch中监测路由一旦路由变化同时增加cacheViews和visitedViewswatch( () route.fullPath, () { addTags() // moveToCurrentTag() } )2过滤有权限的路由中meta.affix为true的路由添加进cacheViews和visitedViewsconst initTags () { const affixTags filterAffixTags(routes.value) console.log(affixTags,affixTags) for (const tag of affixTags) { if (tag.name) { tagStore.addVisitedViews(tag) tagStore.addCacheView(tag.name as string) } } }const filterAffixTags (routes: any[], basePath /) { let tags: TagView[] [] routes.forEach(route { const tagPath basePath / ? route.path : ${basePath}${route.path} if (route.meta.affix) { tags.push({ fullPath: tagPath, path: tagPath, name: route.name, meta: { ...route.meta }, title: route.meta.title || route.name } as TagView) } if (route.children route.children.length) { const childBasePath basePath / ? route.path : ${basePath}${route.path} const tempTags filterAffixTags(route.children, childBasePath) if (tempTags tempTags.length) { tags [...tags, ...tempTags] } } }) return tags }2.添加移除逻辑点击tag中的 x移除时如果移除当前路由那么就要自动切换到他的后一个路由如果移除的当前路由是最后一个那么就切换到前一个const closeTag (tab: TagView) { const nextPathIndex visitedViews.value.findIndex(e { return e.path tab.path }) tagStore.closeVisitedView(tab) // 如果关闭的是当前激活标签则跳转到其他标签 if (props.tagItem.title route.path || props.tagItem.fullPath route.fullPath) { toNextView(visitedViews.value, tab, nextPathIndex) } } const toNextView (visitedViews: TagView[], view: TagView, nextPathIndex: number) { const nextView visitedViews[nextPathIndex] || visitedViews[nextPathIndex - 1] if (nextView) { router.push(nextView.fullPath) } else { // 默认跳转主页 router.push(/) } }3.点击左侧菜单如果上方已有tag则自动定位留到下次再实现在线预览 zy-admin
返回列表