记录--极致舒适的Vue页面保活方案
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助
为了让页面保活更加稳定,你们是怎么做的?
我用一行配置实现了

Vue页面保活是指在用户离开当前页面后,可以在返回时恢复上一次浏览页面的状态。这种技术可以让用户享受更加流畅自然的浏览体验,而不会被繁琐的操作打扰。
为什么需要页面保活?
页面保活可以提高用户的体验感。例如,当用户从一个带有分页的表格页面(【页面A】)跳转到数据详情页面(【页面B】),并查看了数据之后,当用户从【页面B】返回【页面A】时,如果没有页面保活,【页面A】会重新加载并跳转到第一页,这会让用户感到非常烦恼,因为他们需要重新选择页面和数据。因此,使用页面保活技术,当用户返回【页面A】时,可以恢复之前选择的页码和数据,让用户的体验更加流畅。
如何实现页面保活?
状态存储
这个方案最为直观,原理就是在离开【页面A】之前手动将需要保活的状态存储起来。可以将状态存储到LocalStore、SessionStore或IndexedDB。在【页面A】组件的onMounted钩子中,检测是否存在此前的状态,如果存在从外部存储中将状态恢复回来。
有什么问题?
- 浪费心智(麻烦/操心)。这个方案存在的问题就是,需要在编写组件的时候就明确的知道跳转到某些页面时进行状态存储。
- 无法解决子组件状态。在页面组件中还可以做到保存页面组件的状态,但是如何保存子组件呢。不可能所有的子组件状态都在页面组件中维护,因为这样的结构并不是合理。
组件缓存
利用Vue的内置组件<KeepAlive/>缓存包裹在其中的动态切换组件(也就是<Component/>组件)。<KeepAlive/>包裹动态组件时,会缓存不活跃的组件,而不是销毁它们。当一个组件在<KeepAlive/>中被切换时,activated和deactivated生命周期钩子会替换mounted和unmounted钩子。最关键的是,<KeepAlive/>不仅适用于被包裹组件的根节点,也适用于其子孙节点。
<KeepAlive/>搭配vue-router即可实现页面的保活,实现代码如下:
<template>
<RouterView v-slot="{ Component }">
<KeepAlive>
<component :is="Component"/>
</KeepAlive>
</RouterView>
</template>
有什么问题?
- 页面保活不准确。上面的方式虽然实现了页面保活,但是并不能满足生产要求,例如:【页面A】是应用首页,【页面B】是数据列表页,【页面C】是数据详情页。用户查看数据详情的动线是:【页面A】->【页面B】->【页面C】,在这条动线中【页面B】->【页面C】的时候需要缓存【页面B】,当从【页面C】->【页面B】的时候需要从换从中恢复【页面B】。但是【页面B】->【页面A】的时候又不需要缓存【页面B】,上面的这个方法并不能做到这样的配置。
最佳实践
最理想的保活方式是,不入侵组件代码的情况下,通过简单的配置实现按需的页面保活。
【不入侵组件代码】这条即可排除第一种方式的实现,第二种【组件缓存】的方式只是败在了【按需的页面保活】。那么改造第二种方式,通过在router的路由配置上进行按需保活的配置,再提供一种读取配置结合<KeepAlive/>的include属性即可。
路由配置
src/router/index.ts
import useRoutersStore from '@/store/routers'; const routes: RouteRecordRaw[] = [
{
path: '/',
name: 'index',
component: () => import('@/layout/index.vue'),
children: [
{
path: '/app',
name: 'App',
component: () => import('@/views/app/index.vue'),
},
{
path: '/data-list',
name: 'DataList',
component: () => import('@/views/data-list/index.vue'),
meta: {
// 离开【/data-list】前往【/data-detail】时缓存【/data-list】
leaveCaches: ['/data-detail'],
}
},
{
path: '/data-detail',
name: 'DataDetail',
component: () => import('@/views/data-detail/index.vue'),
}
]
}
]; router.beforeEach((to: RouteLocationNormalized, from: RouteLocationNormalized, next: NavigationGuardNext) => {
const { cacheRouter } = useRoutersStore();
cacheRouter(from, to);
next();
});
保活组件存储
src/stroe/router.ts
import { RouteLocationNormalized } from 'vue-router';
const useRouterStore = defineStore('router', {
state: () => ({
cacheComps: new Set<string>(),
}),
actions: {
cacheRouter(from: RouteLocationNormalized, to: RouteLocationNormalized) {
if(
Array.isArray(from.meta.leaveCaches) &&
from.meta.leaveCaches.inclued(to.path) &&
typeof from.name === 'string'
) {
this.cacheComps.add(form.name);
}
if(
Array.isArray(to.meta.leaveCaches) &&
!to.meta.leaveCaches.inclued(from.path) &&
typeof to.name === 'string'
) {
this.cacheComps.delete(to.name);
}
},
},
getters: {
keepAliveComps(state: State) {
return [...state.cacheComps];
},
},
});
页面缓存
src/layout/index.vue
<template>
<RouterView v-slot="{ Component }">
<KeepAlive :include="keepAliveComps">
<component :is="Component"/>
</KeepAlive>
</RouterView>
</template> <script lang='ts' setup>
import { storeToRefs } from 'pinia';
import useRouterStore from '@/store/router'; const { keepAliveComps } = storeToRefs(useRouterStore());
</script>
TypeScript提升配置体验
import 'vue-router';
export type LeaveCaches = string[];
declare module 'vue-router' {
interface RouteMeta {
leaveCaches?: LeaveCaches;
}
}
该方案的问题
- 缺少通配符处理
/*、/**/index。 - 无法缓存
/preview/:address这样的动态路由。 - 组件名和路由名称必须保持一致。
总结
通过<RouterView v-slot="{ Component }">获取到当前路由对应的组件,在将该组件通过<component :is="Component" />渲染,渲染之前利用<KeepAlive :include="keepAliveComps">来过滤当前组件是否需要保活。 基于上述机制,通过简单的路由配置中的meta.leaveCaches = [...]来配置从当前路由出发到哪些路由时,需要缓存当前路由的内容。
本文转载于:
https://juejin.cn/post/7216262593718173752
如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。

记录--极致舒适的Vue页面保活方案的更多相关文章
- 记录一个简单的vue页面实现
<template> <div class="userView"> <!-- 页眉颜色统一 --> <div class="bu ...
- vue中的页面渲染方案
一.模板渲染 <div id="J_render_app"> <ul v-if="items.length"> <li v-for ...
- 本人为项目组制定的一份页面优化指南(easyui页面优化方案)
#本人为项目组制定的一份页面优化指南(easyui页面优化方案) ##背景 这是一篇我之前为项目组制定的页面优化指南,主要是面向表单页面,典型的像[注册用户](https://passport.cnb ...
- python 全栈开发,Day92(编程式的导航,vue页面布局,marked包的使用)
昨日内容回顾 1. 组件间的传值 1. bus --> 空Vue对象 通过向bus对象抛出自定义事件的方式在组件间传递信息 2. 注意事项: 1. bus.$on()应该在组件mounted(挂 ...
- Web开发中,页面渲染方案
转载自:http://www.jianshu.com/p/d1d29e97f6b8 (在该文章中看到一段感兴趣的文字,转载过来) 在Web开发中,有两种主流的页面渲染方案: 服务器端渲染,通过页面渲染 ...
- 《推送开发全面盘点当前Android后台保活方案的真实运行效果》
登录 立即注册 TCP/IP详解 资讯 动态 社区 技术精选 首页 即时通讯网›专项技术区›推送开发全面盘点当前Android后台保活方案的真实运行效果(截止2 ... 帖子 打赏 分 ...
- 【原】移动端vue页面点透事件 - 分析与解决
近期项目遇到了vue页面事件被带到下一个页面的问题,也就是我们常说的点透事件,主要表现在android机器上,花了不少时间折腾,简单做下总结~ vue页面之间的切换通过Vue Router的route ...
- 全面盘点当前Android后台保活方案的真实运行效果(截止2019年前)
本文原作者“minminaya”,作者网站:minminaya.cn,为了提升文章品质,即时通讯网对内容作了幅修订和改动,感谢原作者. 1.引言 对于IM应用和消息推送服务的开发者来说,在Androi ...
- iframe嵌套vue页面打开新窗口
iframe嵌套vue页面时目录结构为下图: 此时出口文件指向index.html, 所以只需要用a标签动态拼接href, 并设置属性 target="_blank" ,即可在if ...
- 2018年Android的保活方案效果统计
一.常见保活方案 1.监听广播:监听全局的静态广播,比如时间更新的广播.开机广播.解锁屏.网络状态.解锁加锁亮屏暗屏(3.1版本),高版本需要应用开机后运行一次才能监听这些系统广播,目前此方案失效.可 ...
随机推荐
- Asp .Net Core 系列:Asp .Net Core 集成 Panda.DynamicWebApi
目录 简介 Asp .Net Core 集成 Panda.DynamicWebApi 配置 原理 什么是POCO Controller? POCO控制器原理 ControllerFeatureProv ...
- React axios 使用 http-proxy-middleware 解决跨域问题小记
壹 ❀ 引 在上篇bug分析的记录文中,提到axios可做到取消接口请求,所以想写一篇关于axios.CancelToken使用以及原理分析的文章(主要是自己好奇到底如何做到的取消).在准备工作阶段, ...
- 2023牛客暑期多校训练营3 ABDHJ
比赛链接 A 题解 知识点:数学. 当 \(x = 0\) 时,当且仅当 \(y = 0\) 可行. 当 \(x \neq 0\) 时,一定可行,答案为 \(|x-y|\) . 时间复杂度 \(O(1 ...
- NC14700 追债之旅
题目链接 题目 题目描述 小明现在要追讨一笔债务,已知有n座城市,每个城市都有编号,城市与城市之间存在道路相连(每条道路都是双向的),经过任意一条道路需要支付费用.小明一开始位于编号为1的城市,欠债人 ...
- 一个让java程序员有杀人的冲动的Xerces冲突问题
History Xerces是Java生态圈使用最广泛的XML解析器,基本上所有的类库和框架都会在一定程度上使用它(即使没有直接引用,也有可能间接引用) Xerces在官网中发布的包是没有标注版本的, ...
- MongoDB Security
1. Security MongoDB提供了一系列的保护措施,以保护它自身安全: 启用访问控制并实行身份验证 MongoDB支持多种身份认证机制,默认的认证机制是SCRAM 配置基于角色的访问控制 ...
- Android上的日志
Android的日志机制和普通的Java项目有一些不一样, 这里记录一下 安卓内建的Log 安卓应用类型(在build.gradle里定义 android {...})的模块, 可以直接引用内建的an ...
- 使用spring boot jpa进行增删改查
项目地址:https://gitee.com/indexman/spring_boot_in_action 编写实体类User package com.laoxu.springboot.entity; ...
- RCE代码执行漏和命令执行漏洞
前置知识: 漏洞检测: 在了解漏洞概念前,应该先知道一下这个漏洞如何检测的,我们应该或多或少听过白盒测试(白盒),黑盒测试(黑盒). 白盒测试: 白盒测试是对源代码和内部结构的测试,测试人员是可以知道 ...
- QT - Day 3
对话框 分类 模态对话框 QDialog dlg(this); dlg.resize(200,100); dlg.exec(); //窗口阻塞 非模态对话框 QDialog *dlg2 = new Q ...
