功能需求
网页端需要做页面数据缓存(vue动态路由数据缓存),可根据id值打开多个编辑详情页,需要在页面操作返回时关闭面包屑页签
隐藏问题
1.页面缓存会有初始化和组件激活访问生命周期调用数据接口过多,有性能损耗
2.使用this.$router.back()
返回是返回上一个历史路由,如果打开多个id详情页,并反复在两个详情页做切换操作,会导致在操作返回时看起来像是在详情页反复切换数据关闭不了,如下图
解决
1.缓存页组件初始化(created
)和组件激活访问(activated
)生命周期只执行一次,使用变量状态,在进入方法时判断变量是否return,在接口完成(finally)更改变量
2.路由历史栈,在路由守卫router.beforeEach
对store
存储from历史路由,在标题组件返回方法里,对历史路由栈数据进行操作,获取历史有效路由使用this.$router.replace
跳转
javascript
//在面包屑页签组件初始化时调用addTags方法存储访问路由
addTags() {
const { name } = this.$route
if (name) {
this.$store.dispatch('tagsView/addView', this.$route)
}
},
//在权限管理路由守卫里存储历史访问路由
import store from './store'
router.beforeEach(async (to, from, next) => {
...
store.commit('tagsView/ADD_ROUTER_HISTORY', from.path);
...
}
tagsView.js文件
javascript
const state = {
visitedViews: [],
cachedViews: [],
routeHistory: [],
closedRoutes: [],
validHistory:[],
lastValidRoute:''
}
const mutations = {
ADD_ROUTER_HISTORY: (state, path) => {
state.routeHistory.push(path);
},
CLOSE_ROUTER(state, route) {
state.closedRoutes.push(route);
// 生成过滤后的有效历史栈
state.validHistory = state.routeHistory.filter(item => !state.closedRoutes.includes(item))
if (state.cachedViews.length===0) {
//首页
state.lastValidRoute = '/'
}else{
//历史有效路由
state.lastValidRoute = state.validHistory[state.validHistory.length - 1];
}
},
ADD_VISITED_VIEW: (state, view) => {
if (state.visitedViews.some(v => v.path === view.path)) return
state.visitedViews.push(
Object.assign({}, view, {
title: view.meta.title || 'no-name'
})
)
},
ADD_CACHED_VIEW: (state, view) => {
if (state.cachedViews.includes(view.name)) return
if (!view.meta.noCache) {
state.cachedViews.push(view.name)
}
console.log(state.cachedViews)
}
}
const actions = {
addView({ dispatch }, view) {
dispatch('addVisitedView', view)
dispatch('addCachedView', view)
},
addVisitedView({ commit }, view) {
commit('ADD_VISITED_VIEW', view)
},
addCachedView({ commit }, view) {
commit('ADD_CACHED_VIEW', view)
},
delView({ dispatch, state }, view) {
return new Promise(resolve => {
dispatch('delVisitedView', view)
dispatch('delCachedView', view)
resolve({
visitedViews: [...state.visitedViews],
cachedViews: [...state.cachedViews],
})
})
},
delVisitedView({ commit, state }, view) {
return new Promise(resolve => {
commit('DEL_VISITED_VIEW', view)
resolve([...state.visitedViews])
})
},
delCachedView({ commit, state }, view) {
return new Promise(resolve => {
commit('DEL_CACHED_VIEW', view)
resolve([...state.cachedViews])
})
}
}
export default {
namespaced: true,
state,
mutations,
actions
}
标题组件layout-header.vue文件返回方法里应用
html
<template>
<div class="layout-header">
<div class="back" v-if="back" @click="handleBack">
<img src="@/assets/images/back-icon.png"/>
</div>
<div class="layout-title" :style="'font-size:' + fontSize + 'px' ">{{title}}</div>
<slot></slot>
</div>
</template>
javascript
<script>
export default {
props: {
title: {
type: String,
default: ""
},
back: {
type: Boolean,
default: false
},
fontSize: {
type: Number,
default: 18
}
},
data() {
return {
}
},
methods: {
handleBack(){
let path = this.$route.path
//存入当前路由
this.$store.commit('tagsView/ADD_ROUTER_HISTORY', path);
const visitedViews=this.$store.state.tagsView.visitedViews
let view = visitedViews.find(v => v.path === path)
//计算路由历史栈及访问路由
this.$store.commit('tagsView/CLOSE_ROUTER', path);
this.$store.dispatch('tagsView/delView', view)
// 获取最近有效路由并跳转
const target = this.$store.state.tagsView.lastValidRoute
this.$router.replace(`${target}`);
}
}
}
</script>