app.vue
入口
利用 vuex
保存缓存记录,如在 store
目录新建 index.js
import Vue from 'vue'
import Vuex from 'vuex'
import _ from 'lodash'
const state = {
historyVirtualRoutes: [], // 自定义虚拟路由栈
include: [], // 缓存集合
exclude: [], // 不缓存集合,确保及时清除缓存
}
const getters = {
historyVirtualRoutes: state => state.historyVirtualRoutes,
include: state => state.include,
exclude: state => state.exclude
}
const actions = {
// 处理缓存问题方法
handleInclude({ commit, dispatch, getters }, { to, from }) {
if (to.params.__routerType === 'push' || to.query.__routerType === 'push') { // push 方法跳转
commit('PUSH_INCLUDE', to.name)
commit('PUSH_HISTORY_VIRTUAL_ROUTES', to)
} else if (to.params.__routerType === 'replace' || to.query.__routerType === 'replace') { // replace 方法跳转
commit('POP_INCLUDE', from.name)
commit('PUSH_INCLUDE', to.name)
commit('POP_HISTORY_VIRTUAL_ROUTES', from)
commit('PUSH_HISTORY_VIRTUAL_ROUTES', to)
} else {
let len = getters.historyVirtualRoutes.length
let flag = len && getters.historyVirtualRoutes[len - 1]['path'] === from.path
if (flag) { // 返回
commit('POP_INCLUDE', to.name)
commit('POP_HISTORY_VIRTUAL_ROUTES')
} else { // 非返回
commit('PUSH_INCLUDE', to.name)
commit('PUSH_HISTORY_VIRTUAL_ROUTES', to)
}
}
// 处理 meta.keepAlive 参数缓存
dispatch('handleIncludeKeepAlive', to)
dispatch('handleIncludeKeepAlive', from)
},
// 处理路由 meta.keepAlive 参数方法
handleIncludeKeepAlive({ commit }, params) {
if (params.meta.hasOwnProperty('keepAlive')) {
if (params.meta.keepAlive === true || params.meta.keepAlive === 'true')
commit('PUSH_INCLUDE', params.name)
else if (params.meta.keepAlive === false || params.meta.keepAlive === 'false')
commit('POP_INCLUDE', params.name)
}
},
// 重置缓存
clearInclude({ commit }) {
commit('CLEAR_INCLUDE')
}
}
const mutations = {
// 虚拟路由栈入栈
'PUSH_HISTORY_VIRTUAL_ROUTES'(state, value) {
state.historyVirtualRoutes.push(value)
},
// 虚拟路由栈出栈
'POP_HISTORY_VIRTUAL_ROUTES'(state, value) {
if (_.isPlainObject(value)) {
let i = _.findLastIndex(state.historyVirtualRoutes, item => item.path === value.path)
if (i !== -1) { // 删除传入的指定路由
state.historyVirtualRoutes.splice(i, 1)
return
}
}
state.historyVirtualRoutes.pop() // 不传默认删除最后一个路由
},
// include 缓存集合入栈,同时需要 exclude 不缓存集合出栈
'PUSH_INCLUDE'(state, value) {
if (!value) return
let i = state.include.indexOf(value)
if (i === -1 && value)
state.include.push(value)
let index = state.exclude.indexOf(value)
if (index !== -1) {
_.remove(state.exclude, item => item === value)
}
},
// include 缓存集合出栈,同时需要 exclude 不缓存集合入栈
'POP_INCLUDE'(state, value) {
let i = state.include.indexOf(value)
if (i !== -1)
_.remove(state.include, item => item === value)
let index = state.exclude.indexOf(value)
if (index === -1 && value)
state.exclude.push(value)
},
// 重置缓存集合
'CLEAR_INCLUDE'(state) {
state.include = []
}
}
Vue.use(Vuex)
export default new Vuex.Store({
state,
getters,
actions,
mutations
})
新建一个 js
文件重写 $router.push
$router.replace
方法,如在 utils
目录新建 router-rewrite.js
import _ from 'lodash'
// 重写 push 方法
export function routerPush(VueRouter) {
const myRouterPush = VueRouter.prototype.push;
VueRouter.prototype.push = function push(location, onComplete, onAbort) {
if (_.isString(location))
location = { path: location, query: { __routerType: 'push' } }
else {
location.params = location.params || {}
if (!location.params.hasOwnProperty('__routerType'))
location.params.__routerType = 'push'
}
return myRouterPush.call(this, location, onComplete, onAbort).catch(error => error)
};
}
// 重写 replace 方法
export function routerReplace(VueRouter) {
const myRouterReplace = VueRouter.prototype.replace;
VueRouter.prototype.replace = function replace(location, onComplete, onAbort) {
if (_.isString(location))
location = { path: location, query: { __routerType: 'replace' } }
else {
location.params = location.params || {}
if (!location.params.hasOwnProperty('__routerType'))
location.params.__routerType = 'replace'
}
return myRouterReplace.call(this, location, onComplete, onAbort).catch(error => error)
};
}
在 router
目录新建 index.js
,对路由 afterEach
阶段进行拦截
import Vue from 'vue'
import VueRouter from 'vue-router'
import { routerPush, routerReplace } from '@/utils/router-rewrite'
import store from '@/store/index'
import _ from 'lodash'
// 初始化重写的 push replace 方法
routerPush(VueRouter)
routerReplace(VueRouter)
Vue.useContext(VueRouter)
// 构建路由
const router = new VueRouter({
mode: 'history',
routes: [
// {
// path: '/text-page',
// name: 'TextPage',
// component: () => import('@/views/text-page'),
// meta: {}
// }
]
})
// 拦截 afterEach 路由
router.afterEach((to, from) => {
if (to.params.hasOwnProperty('keepAliveTo'))
to.meta.keepAlive = to.params.keepAliveTo
else if (to.query.hasOwnProperty('keepAliveTo'))
to.meta.keepAlive = to.query.keepAliveTo
if (to.params.hasOwnProperty('keepAliveFrom'))
from.meta.keepAlive = to.params.keepAliveFrom
else if (to.query.hasOwnProperty('keepAliveFrom'))
from.meta.keepAlive = to.query.keepAliveFrom
// 处理路由传参方法
const changeRoutes = routes => {
return {
fullPath: routes.fullPath,
hash: routes.hash,
name: routes.name,
path: routes.path,
meta: { ...routes.meta },
params: { ...routes.params },
query: { ...routes.query }
}
}
let params = {
to: changeRoutes(to),
from: changeRoutes(from)
}
store.dispatch('handleInclude', params)
})
export default router
在 main.js
注册,如:
import Vue from 'vue'
import App from './app.vue'
import router from './router/index'
import store from './store/index'
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
至此已完成,下面简单说明路由使用方法:
export default {
name: "PageA",
}
- 现在路由默认前进刷新后退缓存,在
.vue
文件直接使用 this.$router.push
this.$router.replace
或 this.$router.back
方法即可,如:
export default {
name: "PageA",
methods: {
// 跳转到测试页面
toTestPage() {
this.$router.push({
name: "TestPage"
});
}
}
};
- 路由跳转时可通过传参
keepAliveTo
或 keepAliveFrom
参数(params
或 query
参数均可)动态实现页面是否缓存
// 例子1:A页面 ==> B页面,A页面跳转到B页面,实现从B页面返回时,A页面也刷新(即不缓存A页面)
// 在A页面跳到B页面时传参 keepAliveFrom
export default {
name: "PageA",
methods: {
// 跳转到B页面
toPageB() {
this.$router.push({
name: "PageB",
params: { keepAliveFrom: false }
});
}
}
};
// 例子2:A页面 ==> B页面,A页面跳转到B页面,从B页面返回A页面或其他页面,再次进入B页面实现B页面缓存(即缓存B页面)
// 在A页面跳到B页面时传参 keepAliveTo
export default {
name: "PageA",
methods: {
// 跳转到B页面
toPageB() {
this.$router.push({
name: "PageB",
params: { keepAliveTo: true }
});
}
}
};
- 通过配置路由时配置
meta.keepAlive
的值控制页面是否缓存。(提示:这种方法不够灵活,如有页面特殊缓存需要推荐使用上面的方法,上面方法本质上也是通过 keepAliveFrom
keepAliveTo
动态设置页面路由 meta.keepALive
的值的)
// 例子1:A页面 ==> B页面,A页面跳转到B页面,实现从B页面返回时,A页面也刷新(即不缓存A页面)
// 配置 PageA 路由时,设置 `meta.keepAlive` 为 `false` 即可,如:
{
path: "/page-a",
name: "PageA",
component: () => import("@/views/page-a"),
meta: {
keepAlive: false
}
}
// 例子2:A页面 ==> B页面,A页面跳转到B页面,从B页面返回A页面或其他页面,再次进入B页面实现B页面缓存(即缓存B页面)
// 配置 PageB路由时,设置 `meta.keepAlive` 为 `true` 即可,如:
{
path: "/page-b",
name: "PageB",
component: () => import("@/views/page-b"),
meta: {
keepAlive: true
}
}