vue 后退不刷新,前进刷新 keep-alive

最近在开发中遇到了这样的一个问题:

A、B、C三个页面,有如下这样的场景:

(1)从页面A离开进入B或C的时候,缓存A页面的数据,并且返回到A后,能保持A页面的跳转前职位

(2)离开B进入C的时候,缓存B

(3)离开B进入A的时候,不缓存

现在开始分步解决:

方案一:

从场景中可是看出A、B是需要缓存的,

首先修改app.vue

<template>
  <div id="app">
    <keep-alive :include="['Index', 'List']">
      <router-view/>
    </keep-alive>
  </div>
</template>

include是A、B页面中的name值,注意,include接受的是数组字符串

然后就是A页面进入B页面的时候刷新,即离开B进入A的时候不缓存,那么就需要用到beforeRouteEnter(),此函数在mounted()执行后执行,不是methods中的自定义函数

export default {
  name: "List",
  beforeRouteEnter(to, from, next) {
      next(vm => {
        // 通过 `vm` 访问组件实例
        if (from.fullPath == '/' && to.fullPath.indexOf('/list') > -1) { //一定是从A进到B页面才刷新
           vm.initFn(); //initFn是本来写在mounted里面的各种, 执行顺序是:先执行mounted,然后是此处
        }
      })
   },
  methods: {
    initFn() {
      ... //获取数据
    }
  } }

返回到原来的位置用到的是router中的scrollBehavior():

router.js:

new Router({
    routes: [],
    scrollBehavior(to, from, savedPosition) {
      // keep-alive 返回缓存页面后记录浏览位置
      if (savedPosition && to.meta.isKeepAlive) {
        return savedPosition;
      }
      // 异步滚动操作
      return new Promise((resolve) => {
        setTimeout(() => {
          resolve({ x: 0, y: 1 });
        }, 0);
      });
    }
})
有时候会有返回不回去的情况,可做延时处理:
new Router({
    routes: [],
    scrollBehavior(to, from, savedPosition) {
      // keep-alive 返回缓存页面后记录浏览位置
      if (savedPosition && to.meta.isKeepAlive) {
         setTimeout(() => { //延时
           window.scrollTo(savedPosition.x, savedPosition.y)
         }, 10);
      }
      // 异步滚动操作
      return new Promise((resolve) => {
        setTimeout(() => {
          resolve({ x: 0, y: 1 });
        }, 0);
      });
    }
})

除了使用keep-alive的include属性,可通过给router中添加mate参数控制

app.vue:

<template>
  <div id="app">
    <keep-alive>
      <router-view v-if="$route.meta.isKeepAlive"/>
    </keep-alive>
    <router-view v-if="!$route.meta.isKeepAlive"/>
  </div>
</template>

注意此处if判断中的meta后的值要与router中的一致

router.js

const router = new Router({
  routes: [
    {
      path: '/',
      name: 'Index',
      component: Index,
      meta: {
        isKeepAlive: true
      }
    },
    {
      path: '/list/:id', 
      name: 'List',
      component: List,
      meta: {
        isKeepAlive: true
      }
    }
  ],
  scrollBehavior(to, from, savedPosition) {
    // keep-alive 返回缓存页面后记录浏览位置
    if (savedPosition && to.meta.isKeepAlive) {
      return savedPosition;
    }
    // 异步滚动操作
    return new Promise((resolve) => {
      setTimeout(() => {
        resolve({ x: 0, y: 1 });
      }, 0);
    });
  }
});
export default router;

当然还有其他的解决方法,如destory()。

方案二:

利用$destroy()销毁:

beforeRouteLeave (to: any, from: any, next: any) {
  // 导航离开该组件的对应路由时调用
  // 判断是否是去往页面 C 
  if (to.name !== 'C') {
    // 不是去 C 页面,不缓存
    this.$destroy()
  }
  next()
}

但bug是销毁后将永远不会再次缓存。

网上还有给出其他方案,查看源码可以发现缓存是通过添加cache属性存储vnode的,如通过源码的cache属性,强制移除某个对象,缺点是没有彻底销毁依旧占内存,不过我没有实验,具体的就不知道了。

还有就是动态设置router.js中的keepAlive值,通过beforeRouteLeave(to, from, next)中的to,from判断url,动态设置keepAlive是true还是false,但设置为true缓存后,即使再设置为false也不会清除缓存,那么会出现bug,列表页不同id的进入,始终是第一次进入时的数据。

经过多次测试,发现方案一的两种写法均是可行且没出现bug的,记录下,方便以后复习

原文地址:https://www.cnblogs.com/cyj7/p/10824522.html