最近产品提出了需求要做页面缓存功能,接到这个需求我第一时间想到的是用keep-alive来实现。在这过程中踩过很多坑也遇到了很多问题;记录下自己遇到的问题,以及对应的解决方法。
方案1:使用keep-alive缓存页面组件
......<keep-alive :include="cachedViews"><router-view :key="key" /></keep-alive>export default {computed: {cachedViews() {return this.$store.state.tagsView.cachedViews},key() {return this.$route.path},}}
这种方案是把菜单页面放到缓存里面,但是这样遇到问题:从A页面跳转B页面,B页面的数据是通过A页面传递参数进行数据渲染的,第n次进来的时候永远是保持第一次进来的状态。因为我们后台管理系统实现方式采用的是动态路由,需要后端配合来完成。我想到的是在菜单加个配置项对每个菜单页面进行配置是否加入缓存,这样可以区分那些菜单是否需要缓存那些不需要缓存。但是后端不同意这样干,觉得只要前端自己处理就行了。而且页面切换的时候拿到的还是之前的数据不是最新数据。后面想是否能重新调用每个子页面的mounted钩子函数重新调用list接口。
方案二:keep-alive + hook方式调用子页面的mounted
......<keep-alive :include="cachedViews"><router-view :key="key" ref="viewPage" @hook:activated="routerActivated" /></keep-alive>.....export default {watch: {$route(val) {// 判断在进入页面的时候,页面是不是缓存状态,即 加入缓存列表之前,是不是就已经是缓存了this.judgeActivated(val)},},methods: {// 重新进入缓存页面 activated阶段重新走mountedrouterActivated() {// 非缓历史存页面,直接return,否则会执行两边mountedif (!this.cachedPage) return// 子页面vue实例const vm = this.$refs.viewPageconst createdCrudHandlers = vm.$options['mounted']if (createdCrudHandlers) {for (let i = 0, j = createdCrudHandlers.length; i < j; i++) {createdCrudHandlers[i].call(vm)}}},// 判断页面是否启用页面钩子judgeActivated(view) {this.cachedPage = this.cachedViews.includes(view.name)},}
这种是缓存每个页面 再对每个页面的mounted重新调用,由于历史原因我们系统有多种规范你适合这么干。
方案三:vuex 缓存搜索条件
store下创建缓存条件js文件
/*** 缓存页面搜索条件* **/const state = {cachedRoutes: {}}const mutations = {SET_CACHED_ROUTES: (state, route) => {const {name, query } = routestate.cachedRoutes[name] = query},DELETE_CACHED_ROUTES: (state, route) => {const {name } = routedelete state.cachedRoutes[name]}}const actions = {setCachedRoutes({commit }, route) {commit('SET_CACHED_ROUTES', route)},delCachedRoutes({commit }, route) {commit('DELETE_CACHED_ROUTES', route)}}export default {namespaced: true,state,mutations,actions,}// src/mixins/index.jsimport {mapActions, mapGetters } from 'vuex'
gettter.js
const getters = {...cachedRoutes: state => state.routerCache.cachedRoutes,}export default getters
src/mixins/index.js
import {mapActions, mapGetters } from 'vuex'...computed: {...mapGetters(['cachedRoutes']),},methods: {...mapActions(['setCachedRoutes']),/*** 设置路由缓存相关配置* @param: queryKey 页面搜索表单对象的key*/setSearchQuery(queryKey) {const name = this.$route.nameif (typeof this.setCachedRoutes === 'function') {this.$store.dispatch('routerCache/setCachedRoutes', {name: name, query: JSON.stringify(this[queryKey]) })}},/*** 获取路由缓存相关配置* @param: queryKey 页面搜索表单对象的key*/getSearchQuery(queryKey) {// 如果使用 路由 的 name属性缓存的话,这里就取当前页面路由的 name值,如果使用了 path 缓存替换即可const name = this.$route.nameconst cachedRoutes = this.cachedRoutes || {}if (cachedRoutes.hasOwnProperty(name)) {const target = JSON.parse(cachedRoutes[name])this[queryKey] = Object.assign({}, target)}}}
这种需要在页面需要缓存的里面调用 setSearchQuery 和 getSearchQuery 方法 分别存和取数据