2021-02-03【技术】聊聊keep-alive组件的使用及其实现原理
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021-02-03【技术】聊聊keep-alive组件的使用及其实现原理相关的知识,希望对你有一定的参考价值。
参考技术A keep-alive定义:keep-alive是Vue.js的一个内置组件。它能够不活动的组件实例保存在内存中,而不是直接将其销毁,它是一个抽象组件,不会被渲染到真实DOM中,也不会出现在父组件链中。
它提供了include与exclude两个属性,允许组件有条件地进行缓存。
这里的component组件会被缓存起来。
举个栗子
在点击button时候,coma与comb两个组件会发生切换,但是这时候这两个组件的状态会被缓存起来,比如说coma与comb组件中都有一个input标签,那么input标签中的内容不会因为组件的切换而消失。
props
keep-alive组件提供了include与exclude两个属性来允许组件有条件地进行缓存,二者都可以用逗号分隔字符串、正则表达式或一个数组来表示。
include: 字符串或正则表达式。只有匹配的组件会被缓存。
exclude: 字符串或正则表达式。任何匹配的组件都不会被缓存。
keep-alive的声明周期执行
页面第一次进入,钩子的触发顺序
created-> mounted-> activated,退出时触发 deactivated
当再次进入(前进或者后退)时,只触发 activated
事件挂载的方法等,只执行一次的放在 mounted 中;组件每次进去执行的方法放在 activated 中;
将缓存name为a的组件。
name为a的组件将不会被缓存。
注意:此处的name值是与在名称为component组件中的name值对应的。
生命钩子
keep-alive提供了两个生命钩子,分别是activated与deactivated。
被keepalive包含的组件不会被再次初始化,也就意味着不会重走生命周期函数
但是有时候是希望我们缓存的组件可以能够再次进行渲染,这时 Vue 为我们解决了这个问题
被包含在 keep-alive 中创建的组件,会多出两个生命周期的钩子: activated 与 deactivated:
activated 当 keepalive 包含的组件再次渲染的时候触发
deactivated 当 keepalive 包含的组件销毁的时候触发
keep-alive是一个抽象的组件,keep-alive会将组件保存在内存中,并不会销毁以及重新创建,所以不会重新调用组件的created等方法,缓存的组件不会被 mounted,为此需要用activated与deactivated这两个生命钩子来得知当前组件是否处于活动状态。
参数理解
keep-alive 可以接收3个属性做为参数进行匹配对应的组件进行缓存:
include 包含的组件(可以为字符串,数组,以及正则表达式,只有匹配的组件会被缓存)
exclude 排除的组件(以为字符串,数组,以及正则表达式,任何匹配的组件都不会被缓存)
max 缓存组件的最大值(类型为字符或者数字,可以控制缓存组件的个数)
注:当使用正则表达式或者数组时,一定要使用 v-bind
遇见 vue-router 结合router使用,缓存部分页面
所有路径下的视图组件都会被缓存
如果只想要router-view里面的某个组件被缓存,怎么办?
1、使用 include/exclude
2、使用 meta 属性
缺点:需要知道组件的 name,项目复杂的时候不是很好的选择
优点:不需要例举出需要被缓存组件名称
使用$route.meta的keepAlive属性:
需要在router中设置router的元信息meta:
说完了keep-alive组件的使用,我们从源码角度看一下keep-alive组件究竟是如何实现组件的缓存的呢?
created钩子会创建一个cache对象,用来作为缓存容器,保存vnode节点。
destroyed钩子则在组件被销毁的时候清除cache缓存中的所有组件实例。
假设这里有 3 个路由: A、B、C。
需求如下:
默认显示 A
B 跳到 A,A 不刷新
C 跳到 A,A 刷新
实现方式如下:
在 A 路由里面设置 meta 属性:
在 B 组件里面设置 beforeRouteLeave:
在 C 组件里面设置 beforeRouteLeave:
这样便能实现 B 回到 A,A 不刷新;而 C 回到 A 则刷新。
防坑指南
1.keep-alive 先匹配被包含组件的 name 字段,如果 name 不可用,则匹配当前组件 components 配置中的注册名称。
2.keep-alive 不会在函数式组件中正常工作,因为它们没有缓存实例。
3.当匹配条件同时在 include 与 exclude 存在时,以 exclude 优先级最高(当前vue 2.4.2 version)。比如:包含于排除同时匹配到了组件A,那组件A不会被缓存。
4.包含在 keep-alive 中,但符合 exclude ,不会调用 activated 和 deactivated。
keep-alive生命周期钩子函数:activated、deactivated
使用<keep-alive>会将数据保留在内存中,如果要在每次进入页面的时候获取最新的数据,需要在activated阶段获取数据,承担原来created钩子中获取数据的任务。
附录,题外话
生命周期函数:就是vue在某个时间段会自动执行的函数
1、beforeCreate()在执行的时候,data还有methods都没有被初始化。
2、created() data还有methods都被初始化好了,如果要调用 methods 方法或者操作 data 里面的数据,最早只能在 created 里面进行操作。
3、beforeMount() 表示模板已经在内存中编辑完成了,但是尚未渲染到模板页面中。即页面中的元素,没有被真正的替换过来,只是之前写的一些模板字符串。
4、mounted() 表示内存中模板已经真实的挂载到页面中去了,用户可以看到渲染好的界面了
注意这是一个生命周期函数的最后一个函数了,执行完这个函数表示 整个vue实例已经初始化完成了,组件脱离了创建阶段,进入运行阶段。
下面是运行期间的两个生命周期函数的钩子:
5、beforeUpdate() 表示我们的界面还没更新 但是data里面的数据是最新的。即页面尚未和最新的data里面的数据保持同步。
6、update() 表示页面和data里面的数据已经包吃同步了 都是最新的。
7、beforeDestory() 当执行这个生命周期钩子的时候 vue的实例从运行阶段进入销毁阶段 此时实例身上的data 还有 methods处于可用的状态。
8、Destoryed() 表示组件已经完全被销毁了 组件中所有的实例方法都是不能用了
简单聊聊架构设计
这个章节简单聊聊架构设计。
很多技术人员,比较热衷技术,认为技术学好了,架构设计就能手到擒来,但是我的一个观点是,脱离业务的技术都是耍流氓,不是说技术不重要,而是技术必须是服务业务的。
架构,可以说是系统的蓝图,是对系统高层次的定义和描述,在一些复杂情况下,架构可以分为面向业务的业务架构和面向计算机(系统)的软件架构。
业务架构主要是从业务方面描述软件系统,定义了系统能够实现的业务。
在业务架构中,动态的内容包括业务流程、节点、输入输出,静态的内容包括业务域、业务模块、单据模型等。
软件架构有两个主要的概念流派:组成派和决策派。
- 组成派认为软件架构是计算组件以及组件之间的交互
- 决策派认为软件架构师一系列有层次的决策
这里贴一下从百度百科搜到的概念:
软件架构所指的就是说相应的系列性的抽象模式,可以为设计大型软件系统的各个方面提供相应的指导。从本质上来看,软件架构是属于一种系统草图。在软件架构所描述的对象就是直接的进行系统抽象组件构成。连接系统的各个组件之间就是做到把组件之间所存在的通讯比较明确与相对细致的实施描述。处于相应的系统实现环节,那么就会使得细化这些抽象组件成为现实的组件,比如可以是具体的某个类或者是对象。从面向对象领域进行分析,那么各个组件之前实施的连接实现往往是接口。 [1] 软件架构为软件系统提供了一个结构、行为和属性的高级抽象,由构件的描述、构件的相互作用、指导构件集成的模式以及这些模式的约束组成。软件架构不仅显示了软件需求和软件结构之间的对应关系,而且指定了整个软件系统的组织和拓扑结构,提供了一些设计决策的基本原理
一般我们在进行软件开发的时候,到技术人员这里都是已经明确好了的开发需求,前面也说过了 从开始如何获取需求、了解需求、分析需求,UML用例建模,业务用例建模、概念用例建模、系统用例建模
通过这篇,我们大致从开头到软件开发之前,了解了系统的一个概貌,知道系统要实现哪些功能。接下来,我们从业务层转到计算机层,针对已经明确的需求,我们该如何在计算机中实现它。
首先,通过需求分析,我们能够确定需求的范围,得到 需求= 功能+质量+约束
的细节内容
很多时候,我们的需求是很多且比较复杂的,面对这么复杂的需求,我们该如何选择,如何确定软件架构,面对这种复杂情况,我们应该确定系统的关键需求,通过关键需求来进行概念性架构设计,我们需要从众多的需求中,找到关键性需求,这些需求对系统有重大的影响,能够决定系统的成败。
这里的关键需求,是横跨了功能、质量、约束。然后通过剩余的需求,我们来验证和完善架构的设计。
概念架构设计
在确认好了需求之后,我们先进行高层设计,通过对关键需求的分析,借助鲁棒图、时序图、状态图、协作图等,对需求场景进行分解,在较高的层次分解系统,称这个步骤为概念架构设计。在概念架构设计阶段,将最关键的设计要素和交互机制确定下来,牢牢抓住重大需求、特色需求、高风险需求,有针对性的设计策略。概念架构界定系统的高层组件和他们之间的关系。这时意在对系统进行适当分解,但不陷入细节。
概念架构设计并不是细化架构,这时候不会牵扯到实际的开发语言、开发框架、接口等,在概念架构设计中,分解出来的是抽象的组件,这些组件没有接口,只有职责。
在概念设计阶段,我们首先通过鲁棒图,对关键功能进行分析,发现关键职责需要的高层抽象类,然后结合时序图、协作图、状态图,对系统进行高层的分解。
细化架构
经过概念设计之后,我们能够在较高的层次,对系统进行了分解,达成了对系统的一个初步设计,接下来,根据概念设计的内容,细化设计,一般可以通过如下5种视图进行:
- 逻辑架构视图,主要是划分职责以及职责间如何协作,就是通过概念分析的结果对系统进行模块划分、接口定义。
在划分模块、子系统时,可以根据下面三个部分进行:
- 进行架构分层(水平拆分)
- 进行分区(垂直拆分,相当于是按照功能进行划分)
- 交互机制,明确各子系统、各模块之间的交互机制,如基于接口编程、消息机制或RPC调用等;
划分模块的几个原则:
- 职责不同的单元划归不同的模块
- 通用性不同的单元划归不同模块
- 需要不同开发技能的单元划归不同模块
- 兼顾工作量相对均衡,进一步划分太大的模块
在逻辑架构设计时,我们就需要定义模块之间的接口,明确各子系统、各模块之间的接口定义;
UML图静态方面可以用包图、类图、对象图描述,动态方面可以使用序列图、、状态图和活动图来描述。
- 开发架构视图:定义了软件开发环境中,软件模块的实际组织方式,具体涉及源程序文件、配置文件、源程序包、编译后的目标文件、第三方库文件等。核心任务是:开发技术选型、程序文件划分到具体工程、程序之间的编译依赖关系。开发架构的设计着重考虑开发期质量属性,如可扩展性、可重用性、可移植性、易理解性和易测试性等。
我们在通过逻辑架构设计得到的是一个对系统的进一步分解和协作,但是这些要落实到详细的工程代码上就需要通过开发架构在实际工程代码中体现之前的设计。
在UML中用组件图,包图来表述. 开发视图和逻辑视图之间可能存在一定的映射关系:比如逻辑层一般会映射到多个程序包等。
- 物理架构视图:定义了“程序”如何映射(安装、部署或烧写等)到“硬件”、“数据“如何在”硬件“上保存和传递以及如何配合完成软件的可靠性、可伸缩性等要求。物理架构必须考虑
功能分布
和数据分布
两个方面。物理架构主要有两个内容:
- 确定物理硬件配置分布方案
- 将程序映射到物理硬件
-
运行架构视图,运行视图关注系统动态运行时,主要是进程以及相关的并发、同步、通信等问题。运行架构视图和开发视图的关系:开发架构视图一般偏重程序包在编译时期的静态依赖关系,而这些程序运行起来之后会表现为对象、线程、进程,运行视图比较关注的正是这些运行时单元的交互问题,在UML中通常用活动图表述。
运行视图比较关注的正是这些运行时单元的交互问题,在UML中通常用活动图表述。
-
数据架构视图,主要设计三个内容:
- 持久化技术选型,持久化技术有文件、关系型数据库等
- 数据存储格式,如列式存储
- 数据分布策略,这是数据架构的难点,是集中式还是分布式,数据分区、复制等
以上是关于2021-02-03【技术】聊聊keep-alive组件的使用及其实现原理的主要内容,如果未能解决你的问题,请参考以下文章