共计 3116 个字符,预计需要花费 8 分钟才能阅读完成。
背景
在日常的业务开发中,遇到了个问题,从一个列表页进入到子页面,当再次返回列表页的时候,用户心愿保留之前的搜寻信息,比方选中了分页为第 4 页或输出的搜寻条件(id)之类的。
列表页 -> 子页面
子页面 -> 列表页(此时保留上次的信息)
思路
利用长久化数据状态,保留之前的记录信息
这是我第一种想到的办法,利用 vuex,cookie,locaStorage,indexdb,用什么样的存储形式,目标只是为了将咱们之前的操作记录保留下来,比方我输出的搜寻信息,我点击列表的分页信息。
流程如下
1⃣️ 首先定义一个配置项,该配置项如下:
const RouterCached = new Map([['ListName', ['OneChildName', 'TwoChildName']]
]);
2⃣️ 在 List 组件的 beforeRouteLeave 钩子中缓存数据
3⃣️ 在 List 组件的 beforeRouteEnter 钩子中读取缓存数据,执行还原操作。这里有个前提是,from 的钩子必须是 RouterCached 对应的路由名称,也就是如果不在配置的表中,咱们革除缓存,不做任何还原操作。
利用 keep-alive 组件
vue 中 keep-alive 介绍
keey-alive 新增了几个重要的属性
借助社区上的解决方案
得出了如下思路
1. 搭配 vue-router,实现组件的缓存
app.vue 文件中利用 include 属性配合 router-view,这里的目标就是对 cachedViews 中的组件进行 keepAlive
cachedViews 在这里是组件的 name 汇合
<template>
<div class="app-main">
<div class="app-container"
id="app-container">
<keep-alive :include="cachedViews">
<router-view :key="key" />
</keep-alive>
</div>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
name: 'AppMain',
computed: {cachedViews() {return this.$store.state.cachedViews;},
key() {return this.$route.path;},
},
});
</script>
2. 封装对 cacheView 的操作
接下来咱们在 store 在对 cacheView 包装几个操作
- 增加须要缓存的 components
- 革除指定已被缓存的 components
- 革除所有被缓存的 components
import {Route} from 'vue-router';
export interface RouteView extends Partial<Route> {title?: string}
const state = {cachedViews: []
};
const mutations = {ADD_CACHED_VIEW: (status, route: RouteView) => {if (status.cachedViews.includes(route.name)) return;
if (route.meta && route.meta.cache) {status.cachedViews.push(route.name);
}
},
DEL_ALL_CACHED_VIEWS: (status) => {status.cachedViews = [];
},
DEL_CACHED_VIEW: (status, route: RouteView) => {const index = status.cachedViews.indexOf(route.name);
if (index > -1) {status.cachedViews.splice(index, 1);
}
},
};
const actions = {addCachedView({ commit}, route: RouteView) {commit('ADD_CACHED_VIEW', route);
},
delAllCachedViews({commit}) {commit('DEL_ALL_CACHED_VIEWS');
},
delCachedView({commit}, route: RouteView) {commit('DEL_CACHED_VIEW', route);
},
};
export default {
state,
mutations,
actions
};
3. 全局钩子拦挡缓存
接下来在全局的路由钩子 router.beforeEach
中退出该办法的逻辑
const handlerCached = (to: RouteView, from: RouteView) => {const { cachedViews} = store.state;
// 革除除列表到详情外的缓存, 列表与详情需 isback 为对方 name
if (!(to.meta.isback && to.meta.isback.includes(from.name))) {store.dispatch('appMain/delAllCachedViews');
}
// 后退时,一一革除缓存链
cachedViews.forEach((name: string, index: number) => {if (name === from.name && cachedViews[index - 1] && cachedViews[index - 1] === to.name) {store.dispatch('appMain/delCachedView', from);
}
});
const {name} = to;
if (name) {store.dispatch('appMain/addCachedView', to);
}
};
4. 路由配置
最初一步,就是须要在路由配置中 meta 字段,增加 isback,cache 字段,这两个字段和办法的思路是统一的。
cache 示意须要缓存的组件(List),
isback 示意从那个组件回到须要缓存的组件(Child)
如下的配置:
[
{
path: 'list',
component: LayoutEmpty,
meta: {
title: '设施管控',
hiddenPage: true,
},
redirect: '/device/list/deviceLists',
children: [
{
path: 'deviceLists',
code: 'deviceLists',
name: 'DeviceLists',
component: DeviceLists,
meta: {
title: 'ListName',
cache: true,
},
hidden: true,
},
{
path: 'detail',
code: 'deviceDetail',
name: 'DeviceDetial',
component: DeviceDetail,
hidden: true,
meta: {
title: 'OneChildName',
onHidden: true,
isback: 'DeviceLists'
},
},
{
path: 'log',
code: 'log',
name: 'Log',
component: Log,
hidden: true,
meta: {
title: 'TwoChildName',
onHidden: true,
isback: 'DeviceLists'
},
},
],
},
]
⚠️注意事项
最初,须要留神一点 isback 对应的名字是须要缓存的名字,在 routerConfig 中为 name,组件中的 name 也须要保持一致。