vue 项目前进刷新后退不刷新解决方案

302 阅读2分钟

背景

解决 vue 项目页面前进刷新后退不刷新的问题,社区中已经有现成的轮子了:vue-page-stack, vue-navigation等。它们默认把所有页面都进行缓存。而我现在维护的项目,使用部分页面进行缓存,直接用上面的库改动较大。

目前需要人工判断导航的目标页面是否缓存,非常不方便,也容易出现问题(譬如在 beforeEnter 钩子中使用 next 跳转到其他页面)。所以我们需要一个折中的方案。

目标

本方案主要实现以下目标:

  1. 页面开发人员决定是否缓存页面
  2. 自动创建、销毁缓存页面(前进刷新,后退不刷新)
  3. 不侵入现有业务

实现

源码

Vue 提供的keep-alive组件,可以帮助我们进行页面缓存,利用include属性,让我们可以灵活的指定哪些页面可以缓存。

当路由前进时,根据条件判断是否缓存对应页面;当路由后退时,删除对应的缓存页面。

通过重写router.pushrouter.replace函数,判断页面前进或后退——调用它们即表示路由前进:

  let _isRouteForward = false

  const _push = router.push.bind(router);
  const _replace = router.replace.bind(router);
  router.push = (...args) => {
    _isRouteForward = true
    _push(...args)
  }
  router.replace = (...args) => {
    _isRouteForward = true
    _replace(...args)
  }

afterEach中,重置_isRouteForward,并缓存页面对应的组件

  router.afterEach((to, from) => {
    _isRouteForward = false

    const matchedInfo = getMatchedComponent(to, router)
    if (!matchedInfo) return

    if (!matchedInfo.id) {
      _store.commit(`${_moduleName}/addKeepAliveComp`, {
        name: matchedInfo.keepAliveName,
        id: Date.now()
      })
    }
  })

beforeEach中,删除已经缓存的组件:

router.beforeEach((to, from, next) => {
    const matchedInfo = getMatchedComponent(to, router)
    if (!matchedInfo) return next()

    if (matchedInfo.id && _isRouteForward) {
      _store.commit(`${_moduleName}/removeKeepAliveComp`, matchedInfo.index)
      return Vue.nextTick(() => next())
    }

    return next()
  })

使用

import Vue from 'vue'
import keepAlivePage from './keep-alive-page'
import store from './store'
import router from './router'

Vue.use(keepAlivePage);
keepAlivePage(router, store);

new Vue({
  router,
  store,
  render(h) {
    return h('keep-alive-page', [
      h('router-view')
    ])
  }
})

更多

本方案有诸多不足,只解决了公司项目的一些些痛点,更推荐大家使用vue-navigation等库。

另外,如果只考虑使用history模式,还可以在vue-router实例化之前,监听popstate事件,判断浏览器后退。

let _isRouteBack = false

window.addEventListner('popstate', () => {
  _isRouteBack = true
})