写点什么

vue keep-alive(1):vue router 如何保证页面回退页面不刷新?

发布于: 33 分钟前

在构建 SPA 应用时,经常遇到的场景就是列表页面 跳转到详情页,但是详情页面回退到列表页面,列表页面有重新刷新了。

如何保证回退的时候不刷新页面呢?keep-alive 是一个非常好的解决方案(当然你也可以以子路由,以绝对定位形势覆盖上去*_*)。

keep-alive 的作用

keep-alive 是 Vue 的内置组件,能在组件切换过程中将状态保留在内存中,防止重复渲染 DOM。

本篇主要讲 keep-alive 的用法。

keep-alive 用法

像 Tabs 加载动态组件(有的童鞋直接用动态组件取代路由功能——个人不推荐)

缓存组件

<keep-alive> <component include="a" exclude="b">  <!-- name 为 a 的组件将被缓存!,name 为 b 的组件不被缓存! --> </component></keep-alive>
复制代码

缓存路由

<keep-alive include="a">  <router-view>    <!-- 只有路径匹配到的视图 a 组件会被缓存! -->  </router-view></keep-alive>
复制代码

推荐用法:不需要例举出需要被缓存组件名称

<keep-alive>  <router-view v-if="$route.meta.keepAlive">    <!-- 这里是会被缓存的视图组件,比如 Home! -->  </router-view></keep-alive><router-view v-if="!$route.meta.keepAlive">  <!-- 这里是不被缓存的视图组件,比如 Edit! --></router-view>
复制代码

其实就是用 keep-alive 包括原来的组件即可,包括的组件并不像普通组件的那样,slot。keep-alive 只是一个抽象组件。具体看下篇的《vue keep-alive(2):剖析keep-alive的实现原理—学习笔记整理》。

keep-alive 的 props

  • include - 字符串或正则表达,只有匹配的组件会被缓存

  • exclude - 字符串或正则表达式,任何匹配的组件都不会被缓存

  • max- 缓存组件的最大个数,超出上限使用LRU的策略置换缓存数据。

keep-alive+vue 组件声明周期+路由守卫

keep-alive 的作用是在内存中缓存组件(不让组件销毁),等到下次再渲染的时候,还会保持其中的所有状态。

注意:实际保存在内存中的不是渲染后的 HTML 的节点字符串,而是 vue 编译后虚拟化的 DOM 对象

目的是防止重复渲染 DOM,当数据发生了变化时,才会促发 VM 的 diff 更新。

vue 所有功能的实现都是围绕其生命周期进行的,在生命周期的不同阶段调用对应的钩子函数可以实现组件数据管理和 DOM 渲染两大重要功能

keep-alive 缓存了组件,但是它也阻挡了 vue 正常的生命周期流程

vue 的生命周期有:beforeCreate,created,beforeMonted,mounted,beforUpdate,update,beforDestroy,destroyed,详情参看《vue2.x入坑总结—回顾对比angularJS/React

当在不同页面/组件之间切换的时候都会请求一些请求过的数据,每次请求都会导致重复渲染影响性能。这些数据可以存到缓存中——此时使用 keep-alive 将组建包裹起来,但这样以上八种生命周期钩子将失效。

取而代之的是 activate 和 deactivated,在 2.2.0 及其更高版本中,activated 和 deactivated 将会在 树内的所有嵌套组件中触发

  • activate:是在被包裹组建被激活的状态下使用的生命周期钩子(每次组件被调用时都会执行 activated——包括第一次)。

    第一次进入缓存路由/组件:beforeRouteEnter > beforeCreate > created > mounted > activated > ... ... > beforeRouteLeave > deactivated

    再次进入组件时:beforeRouteEnter > activated > ... ... > beforeRouteLeave > deactivated

  • deactivated:在被包裹组件停止使用时调用

理论上:当在项目中引入 keep-alive 的时候,

  • 页面第一次进入,钩子函数的触发顺序 created -> mounted -> activated,

  • 退出时触发 deactivated。

  • 再次进入(前进或者后退)时,只触发 activated。如果 created 或 mounted 中处理刷新页面,这个钩子没有被调用,无法刷新。

beforeRouteEnter 总会触发

  • 不使用 keep-alive 时,

    beforeRouteEnter --> created --> mounted --> destroyed

  • 使用 keep-alive 时,

    beforeRouteEnter --> created --> mounted --> activated --> deactivated

更多的坑,推荐看

《Vue生命周期全解(vueRouter,keep-alive,生命周期)

Vue 爬坑之旅 -- keepAlive 与 vue-router 结合使用实现页面缓存及记住滚动位置功能的实现及几个需要注意的点

keep-alive activate 在项目中应用

一般不只是点到详情页,然后直接返回怎么简单

状态刷新

比如你在详情页面添加到了购物车,列表页面需要展示购车数量等,需要结合 vuex 实现。

更多的是,每次进入这个页面,必须请求后台一些数据,就需要在 activate 里面实现

有发现有个同事的实现是:页面离开,settimeout,臆测一个时间去通知列表页面,去进行操作。这个,嗯,能行,但是绝对不靠谱!

滚动条复位

可以通过:vue-keep-scroll-position 组件解决。但是这个组件,只有刷新路由的容器。如果是页面里面一个列表需要刷新呢?

在需要缓存的页面,如列表页面的 beforeRouteLeave,存储滚动条位置信息。其他操作原理类同。

// 离开时beforeRouteLeave(to: any, from: any, next: any) {    //let  dom: HTMLElement|null = document.getElementById('list');     let dom = this.$refs.list;     // 离开时,想办法存储滚动位置。     to.meta.scrollTop = dom.scrollTop;     }// 返回时activated() {  // 激活后,更加存储的信息,重新设置滚动条  const scrollTop = this.$route.meta.scrollTop;    if (scrollTop) {      this.$nextTick(() => {        this.$refs.list.scrollTop = scrollTop;      });    }}
复制代码

这里需要注意的是,不要通过监听 scroll 事件,在列表页面实时刷新滚动条位置信息——没有必要的性能消耗。

keep-alive 缓存页面限制

仅当从 B 页面回退到 A 页面,恢复 A 页面之前的缓存转态。说个常见的案例吧


从面板页面跳转到编辑页面,需要缓存面板页面。即:从编辑页面回退到面板页面,面板页面还是之前的那个骚年(进入前的样子)。

面板页面

export default [  {    path: '/panel/:biz_id',    name: 'panel',    component: () => import(/* webpackChunkName: "panel-page-chunk" */'@/pages/panel/index.vue'),    children: [      {        path: 'list_panel/:os_id',        name: 'listPanel',        component: () => import(/* webpackPrefetch: true */ /* webpackChunkName: "panel-page-chunk" */'@/pages/panel/list.vue'),        props: route => ({          osId: route.params.os_id,        }),        meta: {          keepAlive: true,        },      },      {        path: 'panel-info',        name: 'panel-info',        component: () => import(/* webpackPrefetch: true */ /* webpackChunkName: "panel-page-chunk" */'@/pages/panel/info.vue'),      },    ],  },  {    path: '/panel/:biz_id/chart_editor/:os_id/:chart_id?',    name: 'chartEditor',    component: () => import(/* webpackPrefetch: true */ /* webpackChunkName: "panel-page-chunk" */'@/pages/panel/chartEditor.vue'),    meta: {      keepAlive: false,    },    props: route => ({      osId: route.params.os_id,    }),  },];
复制代码

需要在面板页面里面,beforeRouteLeave 设置,from.meta.keepAlive = false;

在编辑页面,beforeRouteLeave 设置,to.meta.keepAlive = true;

这个其实是一般方案,如《缓存之keep-alive的理解和应用》,个人觉得这个方案比较好《vue组件缓存之keep-alive正确使用姿势》,其实就是在路由的 meta 设置 路径的权重。如一级页面权重 100,二级页面 1000,三级页面 1000。根据权重去做页面缓存与 页面切换动画的滑动方向。

keep-alive 需要注意的地方总结

  • 先匹配被包含组件的 name 字段,如果 name 不可用,则匹配当前组件 components 配置中的注册名称。 

  • 不会在函数式组件中正常工作,因为它们没有缓存实例。 

  • 当匹配条件同时在 include 与 exclude 存在时,以 exclude 优先级最高(当前 vue 2.4.2 version)。比如:包含于排除同时匹配到了组件 A,那组件 A 不会被缓存。 

  • 包含在 include 中,但符合 exclude ,不会调用 activated 和 deactivated


参考文章:

vue 学习---生命周期钩子 activated,deactivated https://www.cnblogs.com/mengtong/p/10966955.html

vue 页面回退 mounted 函数不执行的问题及解决方法 https://www.cnblogs.com/candy-xia/p/11425357.html

深入理解 vue-router 之 keep-alive https://www.jb51.net/article/122570.htm

官方:<keep-alive>组件缓存问题 #811 https://github.com/vuejs/vue-router/issues/811#issuecomment-353875880

转载本站文章《vue keep-alive(1):vue router如何保证页面回退页面不刷新?》,请注明出处:https://www.zhoulujun.cn/html/webfront/ECMAScript/vue/8236.html

发布于: 33 分钟前阅读数: 2
用户头像

还未添加个人签名 2021.06.25 加入

还未添加个人简介

评论

发布
暂无评论
vue keep-alive(1):vue router如何保证页面回退页面不刷新?