使用场景
譬如a页面跳转b页面,我们需要将a页面缓存,当从b页面回到a页面时,页面不刷新。而a页面跳转c、d等等页面时,不进行缓存。
技术栈及实现原理
本教程基于Vue框架,配合Vue-Router和Vuex进行实现。我们知道,Vue-Router可以使用标签进行页面缓存,还可以配置include属性指定缓存的页面。原理步骤如下:
- 首先配置需要缓存的页面路由名称及目标路由路径。例如:routerName: ["/pageB"];
- 在页面加载前,通过路由组件钩子beforeRouteEnter读取配置,判断当前页面是否需要缓存,即配置文件中是否有配置项的routerName等于当前页面的Name。如果需要缓存,则通过Vuex保存起来;
- 当页面离开时,通过路由组件钩子beforeRouteLeave读取配置,判断将要到达的页面是否需要将当前页面缓存,即数组值是否包含将要到达的路由路径。如果包含,则将当面页面缓存,并通过Vuex在缓存页面列表中新增当前页面;否则将当前页面置为不缓存,并在缓存页面列表中将当前页面移除。
具体实现步骤
这里以用户管理为例:
-
新建三个页面list.vue, edit.vue, detail.vue
list.vue
<template> <div> <div class="app-container"> <p>这是用户列表页</p> <p>模拟缓存数据:</p> <el-input v-model="username" placeholder="请输入用户名" /> </div> </div> </template> <script> export default { name: "UserList", data() { return { username: "" }; } }; </script>
edit.vue
<template> <div> <div class="app-container"> <p>这是用户编辑页</p> <el-input v-model="username" placeholder="请输入用户名" /> </div> </div> </template> <script> export default { name: "UserEdit", data() { return { username: "" }; } }; </script>
detail.vue
<template> <div> <div class="app-container"> <p>这是用户详情页</p> <span>test detail</span> </div> </div> </template> <script> export default { name: "UserDetail" }; </script>
-
配置这三个页面的路由:
{ path: '/test', component: Layout, meta: { title: 'test', icon: 'documentation', affix: true }, children: [ { path: 'user', component: SecondLayout, meta: { title: '用户管理', icon: 'documentation', affix: true }, children: [ { path: 'list', name: 'UserList', component: () => import('@/views/test/user/list'), meta: { title: '用户列表', icon: 'documentation', affix: true } }, { path: 'edit', name: 'UserEdit', component: () => import('@/views/test/user/edit'), meta: { title: '用户编辑', icon: 'documentation', affix: true } }, { path: 'detail', name: 'UserDetail', component: () => import('@/views/test/user/detail'), meta: { title: '用户编辑', icon: 'documentation', affix: true } } ] } ] }
-
配置缓存文件,这里以用户列表页跳转用户编辑页为例。在utils文件夹中新建文件conf.js,增加如下代码:
// 页面缓存配置 export const PageCacheConfig = { // 当前需要缓存的路由名称:['跳转的路由路径'] UserList: ['/test/user/edit'] }
即表示:用户列表页UserList跳转到用户编辑页(路径为‘/test/user/edit’)时需要将用户列表页缓存。
-
利用Vuex在store文件夹中新增页面缓存模块pageCache.js,代码如下:
const state = { pageCacheList: [] }; const getters = { getPageCacheList: state => { return state.pageCacheList; } }; const mutations = { ADD(state, pageName) { state.pageCacheList.push(pageName); }, DEL(state, pageName) { state.pageCacheList.forEach((page, index) => { if (page === pageName) { state.pageCacheList.splice(index); } }); } }; const actions = { add({ commit }, pageName) { commit("ADD", pageName); }, delete({ commit }, pageName) { commit("DEL", pageName); } }; export default { namespaced: true, state, getters, mutations, actions };
-
在你的router-view中配置keep-alive和include:
<template> <div> <keep-alive :include="pageCache"> <router-view v-if="$route.meta.keepAlive" /> </keep-alive> <router-view v-if="!$route.meta.keepAlive" /> </div> </template> <script> import { mapGetters } from "vuex"; export default { name: "SecondLayout", computed: { ...mapGetters({ pageCacheList: "pageCache/getPageCacheList" }), pageCache() { return this.pageCacheList.join(","); } } };
特别说明:因为include中包含的其实是页面导出名称而不是路由名称,而本教程配置的又是路由 名称,因此需要将页面名称与路由名称相匹配
- 新建一个mixin文件pageCacheMix.js:
import { PageCacheConfig } from "@/utils/conf"; import { mapActions, mapGetters } from "vuex"; export default { name: "pageCacheMix", computed: { ...mapGetters({ pageCacheList: "pageCache/getPageCacheList" }) }, methods: { ...mapActions({ addPageCache: "pageCache/add", deletePageCache: "pageCache/delete" }) }, beforeRouteEnter(to, from, next) { next(vm => { if (to.name && PageCacheConfig[to.name]) { if (vm.pageCacheList.includes(to.name)) { // no } else { to.meta.keepAlive = true; vm.addPageCache(to.name); } } }); }, beforeRouteLeave(to, from, next) { // 当前路由配置了路由名以及缓存配置中配置了该路由才进行相关操作 if (from.name && PageCacheConfig[from.name]) { if (PageCacheConfig[from.name].includes(to.path)) { // 配置中包含前往路径,则缓存,否则不缓存 from.meta.keepAlive = true; if (this.pageCacheList.includes(from.name)) { // no } else { this.addPageCache(from.name); } } else { from.meta.keepAlive = false; this.deletePageCache(from.name); } } next(); } };
- 在userList页面中引入pageCache混入文件:
<template> <div> <div class="app-container"> <p>这是用户列表页</p> <p>模拟缓存数据:</p> <el-input v-model="username" placeholder="请输入用户名" /> </div> </div> </template> <script> import pageCacheMix from "@/mixins/pageCacheMix"; export default { name: "UserList", mixins: [pageCacheMix], data() { return { username: "" }; } }; </script>
- finish