vue缓存页面的解决方案

时间:2020-9-6 作者:admin

背景

在日常的业务开发中,遇到了个问题,从一个列表页进入到子页面,当再次返回列表页的时候,用户希望保留之前的搜索信息,比如选中了分页为第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新增了几个重要的属性

vue缓存页面的解决方案

借助社区上的解决方案
得出了如下思路

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也需要保持一致。

声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。