vue2 移动端实现前进刷新、后退缓存

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')

至此已完成,下面简单说明路由使用方法:

  • 页面必须添加 name 属性,如:
export default {
  name: "PageA",
}
  • 现在路由默认前进刷新后退缓存,在 .vue 文件直接使用 this.$router.push this.$router.replacethis.$router.back 方法即可,如:
export default {
  name: "PageA",
  methods: {
    // 跳转到测试页面
    toTestPage() {
      this.$router.push({
        name: "TestPage"
      });
    }
  }
};
  • 路由跳转时可通过传参 keepAliveTokeepAliveFrom 参数(paramsquery 参数均可)动态实现页面是否缓存
// 例子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
  }
}

你可能感兴趣的:(vue,js)