app.vue
入口
vuex
保存缓存记录,如在 store
目录新建 index.js
import { createStore } 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', from.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 = []
}
}
export default createStore({
state,
getters,
actions,
mutations
})
js
文件重写 router.push
router.replace
方法,如在 utils
目录新建 use-router.js
注意:vue-router
在 4.1.4及以上
版本params
参数会失效,此时需要将params
传参修改为query
传参
import { useRouter } from 'vue-router'
// 重写 push replace 方法
export const _useRouter = function () {
const router = useRouter()
console.log(router);
// 重写 push
const _push = router.push
router.push = function push(to) {
if (_.isString(to))
to = { path: to, query: { __routerType: 'push' } }
else {
to.params = to.params || {}
if (!to.params.hasOwnProperty('__routerType'))
to.params.__routerType = 'push'
}
return _push.call(this, to)
}
// 重写 replace
const _replace = router.replace
router.replace = function replace(to) {
if (_.isString(to))
to = { path: to, query: { __routerType: 'replace' } }
else {
to.params = to.params || {}
if (!to.params.hasOwnProperty('__routerType'))
to.params.__routerType = 'replace'
}
return _replace.call(this, to)
}
return router
}
router
目录新建 index.js
,对路由 afterEach
阶段进行拦截import store from '@/store/index'
import { createRouter, createWebHistory } from 'vue-router'
import _ from 'lodash'
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes: [
// {
// path: '/test',
// name: 'Test',
// component: () => import('../views/Test.vue')
// },
]
})
// 路由 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 = routeObj => {
return {
fullPath: routeObj.fullPath,
hash: routeObj.hash,
name: routeObj.name,
path: routeObj.path,
meta: { ...routeObj.meta },
params: { ...routeObj.params },
query: { ...routeObj.query }
}
}
let params = {
to: changeRoutes(to),
from: changeRoutes(from)
}
store.dispatch('handleInclude', params)
})
export default router
main.js
注册,如:import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
const app = createApp(App)
app.use(store) // 挂载 vuex
app.use(router) // 挂载路由
app.mount('#app')
name
属性,如:import { defineComponent } from "vue";
export default defineComponent({
name: "PageA"
});
import { defineComponent } from "vue";
import { useRouter } from "vue-router";
export default defineComponent({
name: "PageA",
setup() {
const router = useRouter();
// 跳转到 PageTest 页面
const toPageTest = () => {
router.push({ name: "PageTest " });
};
return {
toPageTest
};
}
});
keepAliveTo
或 keepAliveFrom
参数(params
或 query
参数均可)动态实现页面是否缓存// 例子1:A页面 ==> B页面,A页面跳转到B页面,实现从B页面返回时,A页面也刷新(即不缓存A页面)
// 在A页面跳到B页面时传参 keepAliveFrom
import { defineComponent } from "vue";
import { useRouter } from "vue-router";
export default defineComponent({
name: "PageA",
setup() {
const router = useRouter();
// 跳转到 PageB 页面
const toPageB = () => {
router.push({
name: "PageB",
params: { keepAliveFrom: false }
});
};
return {
toPageB
};
}
});
// 例子2:A页面 ==> B页面,A页面跳转到B页面,从B页面返回A页面或其他页面,再次进入B页面实现B页面缓存(即缓存B页面)
// 在A页面跳到B页面时传参 keepAliveTo
import { defineComponent } from "vue";
import { useRouter } from "vue-router";
export default defineComponent({
name: "PageA",
setup() {
const router = useRouter();
// 跳转到 PageB 页面
const toPageB = () => {
router.push({
name: "PageB",
params: { keepAliveTo: true }
});
};
return {
toPageB
};
}
});
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
}
}