vue部分页面需要缓存,部分不需要缓存,vue关闭页面清除缓存
本文主要介绍如何在vue中管理缓存页面,帮助你更好的理解和学习使用Vue框架。感兴趣的朋友可以了解一下。
目录
问题1销毁1。如何摧毁它
2.它什么时候会被摧毁
2.1方案1使用route.query记录当前页面堆栈深度。
2.2方案2使用Vue实例本身来记录当前堆栈深度
2.3方案3使用history.state记录堆栈深度。
两个问题:在同一个页面上缓存不同参数的多个实例1。如何做到独一无二?
1.1时间戳,超级随机数1.2路由栈高路径名2。如何给页面的vnode赋值?
2.1通过route.query动态绑定密钥
2.2通过获得Vnode直接分配
摘要
点火电极
路由器-视图/
/保持活力
Vue内置的keep-alive组件可以帮助我们在开发SPA应用时缓存所有的路由页面(当然也可以有目的的缓存部分页面),可以显著提高二次页面访问的速度。然而,它也给我们带来了一些麻烦,包括两个主要矛盾:
如何在合适的时间销毁缓存页面(keep-alive组件提供了三个参数来动态配置缓存状态,但其作用有限,后面会分析)
如何缓存同一个路径下多个不同的页面(同一个页面上不同的引用),比如淘宝商品页面继续跳转到另一个商品页面?
本文主要围绕这两个问题展开,以下简称为问题1和问题2。
默认情况下,本文中的所有页面都保持活动状态。
问题一 销毁
随着业务逻辑变得复杂,路由栈逐渐上升,理论上用户可以无限路由。不可避免地,我们需要管理缓存在内存中的页面数据。页面数据包含两部分,Vue实例和相应的Vnode。查看Vue源代码中src/core/components/keep-alive . js中缓存的定义。
this . cache=object . create(null)//用于缓存vnode cache[key]=Vnode
This.keys=[] //用于记录缓存的vnode的键
缓存后,Vnode将不会被重用,而只是装载在它上面的Vue实例。
if(缓存[键]) {
vnode . component instance=cache[key]。component instance//只从缓存的vnode中获取vue实例,挂在新的vnode上。
//使当前密钥最新
移除(钥匙,钥匙)
按键(按键)
}
为什么不呢?由于一个BUG,实现的最早版本确实直接使用了缓存的Vnode。
来自src/core/components/keep-alive . js初始版本
导出默认值{
已创建(){
this.cache=Object.create(null)
},
render () {
const childNode=this。$slots.default[0]
const cid=child node . component options . ctor . cid
if (this.cache[cid]) {
const child=child node . child=this . cache[cid]。子//直接获取缓存的vnode
childNode.elm=this。$el=孩子。$el
}否则{
this.cache[cid]=childNode
}
childNode.data.keepAlive=true
返回子节点
},
销毁前(){
for(this . cache中的常量键){
this.cache[key].child.$destroy()
}
}
}
我们需要管理的实际上是缓存和键。keep-alive提供了三个参数来动态管理缓存:
仅包含名称匹配的组件将被缓存。
排除-任何具有匹配名称的组件都不会被缓存。
max-可以缓存的组件实例的最大数量。
它们的功能非常简单,源代码也很容易阅读:
所以当我们要管理这些缓存的时候,简单的解决方法就是操作这三个参数,修改include和exclude来缓存或者清除一些缓存,但是需要注意的是,它们与组件的名称相匹配:
来自src/core/components/keep-alive . js
常量名称:string=get component name(component options)
所以清空缓存会无差别的清空一个组件的所有实例,这显然不符合我们的需求。
Max的逻辑是当超过最大值时清除堆栈底部的缓存,
来自src/core/components/keep-alive . js:
if(this . max keys . length parse int(this . max)){
pruneCacheEntry(cache,keys[0],keys,this。_vnode)
}
我们必须解决第一个问题。政府提供的API不管用,只能自己来。我们需要解决两个子问题:
它什么时候会被摧毁
怎么破坏?
1. 怎么销毁
先看看怎么破坏吧。如果你想销毁一个实例,你可以使用这个。$destroy()直接。这样可以吗?不会,所以原来的vnode和key还是保存在cache和keys里,再次访问的时候会有问题。vnode被保留了,但是它上面的实例被销毁了。此时,在vue的更新过程中,会创建另一个vue实例。也就是说,只要这个。$destroy()被某个keep-alive页面调用一次,但是缓存数组没有清理干净,这个页面重新渲染的时候肯定会重新创建,当然也会重新经历整个生命周期。最终的结果是这个页面好像没有缓存。
这个。$ destroy();//不适合保持活动状态的组件
所以销毁的时候需要同时清除缓存和密钥。下面定义了一个$keepAliveDestroy方法来同时清除缓存:
const dtmp=vue . prototype . $ destroy;
const f=function() {
如果(这个。$vnode这个。$vnode.data.keepAlive) {
如果(这个。$vnode.parent this。$ vnode . parent . component instance this。$ vnode . parent . component instance . cache){
如果(这个。$vnode.componentOptions) {
var key=!isDef(这个。$vnode.key)
?这个。$ vnode . component options . ctor . cid(this。$vnode.componentOptions.tag?`:$ {这个。$vnode.componentOptions.tag} `: )
:这个。$ vnode.key
var cache=this。$ vnode . parent . component instance . cache;
var keys=this。$ vnode . parent . component instance . keys;
if(缓存[键]) {
if (keys.length) {
var index=keys . index of(key);
if (index -1) {
keys.splice(索引,1);
}
}
删除缓存[键];
}
}
}
}
dtmp.apply(this,arguments);
}
vue . prototype . $ keepAliveDestroy=f;
2. 什么时候销毁
那么什么时候销毁呢?有两个触发时间:
更换时,A页-更换-B页(清除A页)
返回路线,页面A -推送-页面B -返回-页面A(清除页面B)
替换相对简单。我们可以直接拦截router的replace方法,用这个方法清空当前页面。(这里也有例外,比如切换Tab的时候,到最后再说吧)
我们来具体看一下route back的情况。如果我们的页面上有back键,那么清除这里的缓存是一个非常正确的时机,但是我们不能忽视浏览器自带的back键和Android上的物理back键。考虑到这种情况后,只使用back键的方案就不能满足了。
2.1 方案一 使用route.query 记录当前页面栈深度
每次推送或替换时,都会添加query的前一个参数来记录当前深度。
这个。$router.push({
路径:“/targer”,
查询:{
stackLevel:数字(这个。$route.query.stackLevel) 1
}
})
这个方案有明显的缺点。对外暴露一个参数是非常丑陋和危险的,用户可以随意修改。在推广网页时,商家复制到制作环境本身的推广链接也可能带有奇怪的https://xxx.com/foo? Bar=123 stack level=13后缀。放弃
2.2 方案二 使用Vue实例自身记录当前栈深度
黑客攻击路由器的push和replace方法后,每次跳转都可以挂载一个_stackLevel到目标页面的vm上,这样就解决了方案一不暴露给用户,在URL中不可见,无法修改的问题。但是,我们不能忽视浏览器中的另一个恶魔3354刷新键。刷新时URL不会改变,但是需要重新创建vm实例,所以我们的栈深度标记会丢失。放弃
2.3 方案三 使用history.state记录栈深度
最终不仅能让用户看不到,刷新时还能保存。那是history.state,所以我们要做的就是将栈深度保存到history.state中,这样可以完整的保存整个路由链。
当我们得到目标页面的堆栈深度小于当前页面时,我们可以销毁当前页面。
if(target.stack current.stack){
当前。$ keepAliveDestroy();
}
问题二 同页不同参缓存多个实例
可以在源代码中看到src/core/components/keep-alive . js。
常量键:string=vnode.key==null
//同一个构造函数可能被注册为不同的本地组件
//所以只有国际开发委员会是不够的(#3269)
?组件选项. Ctor.cid (componentOptions.tag?`:${componentOptions.tag} `: )
:vnode.key
如果(缓存[键]) {
vnode。组件实例=缓存[键].件实例
//使当前密钥最新
移除(钥匙,钥匙)
按键(按键)
}否则{
cache[key]=vnode
按键(按键)
//删除最旧的条目
如果(这个。最大键数。长度解析int(this。最大)){
pruneCacheEntry(cache,keys[0],keys,this ._vnode)
}
}
一个虚拟节点如果没有键才会使用组件名,所以默认缓存中的键是组件名,如果组件相同时,我们在每个页面都有自己的键就可以解决这个问题了,如何实现每个页面拥有自己的键呢。有两个子问题:
如何做到唯一
如何把键赋值给页面的虚拟节点
1. 如何做到唯一
1.1 时间戳、超大随机数
key=Date.now()
1.2 路由栈高度+路径名
key=vm ._堆叠路由器。电流输出。小路这个方案利用当前的栈高度路径名,为什么需要路径名呢,因为替换的时候栈高度不变,只是路径名变了。
2. 如何把key赋值给页面的vnode
目前有两个方案给某视频剪辑软件路由器当前的虚拟节点的键来赋值:
2.1 通过route.query动态绑定Key
这个方案实现比较简单
//绑定键
.
router-view:key= $ route。查询。路由器密钥/
.
//推送时
这个. router.push({
路径:"/foo ",
查询:{
routerKey: Date.now() //随机键
}
})
这种方式用起来非常简单有效,但是缺点同样也是会暴露一个奇怪的参数在统一资源定位器中
2.2 通过获取到Vnode直接赋值
在哪个阶段给虚拟节点的键赋值呢,答案显而易见,在点火电极组件提出函数进入前,src/core/components/keep-alive。射流研究…
.
render () {
常量槽=这个.$slots.default
const VNode:VNode=getFirstComponentChild(slot)
.
我们可以砍掉点火电极的提出函数,然后在这之前先把狭槽里的第一个子节点拿到以后,给它的键进行赋值,然后再调用点火电极的渲染:
const tmp=vm .$options.render //vm是保持活动的组件实例
虚拟机.$options.render=function() {
常量槽=这个.$ slots.default
const vnode=getFirstComponentChild(slot)//vnode是保活组件虚拟节点
if (historyShouldChange) {
如果(!isDef(vnode.key)) {
如果(isReplace) {
vnode.key=genKey(路由器. stack)
} else if (isPush()) {
vnode.key=genKey(编号(路由器. stack) 1)
}否则{
vnode.key=genKey(编号(路由器. stack) - 1)
}
}
}否则{
//当历史应该改变为错误的时,应仅重新呈现,不应创建新的虚拟机,使用相同的vnode .关键问题#7
vnode.key=genKey(路由器. stack)
}
返回tmp.apply(this,参数)
}
总结
通过以上对于问题的分析,我们就解决了自动管理缓存的核心难题。本文是对开源库vue-路由器-保活-助手的一次总结,此库是款简单易用的点火电极缓存自动化管理工具,从此告别某视频剪辑软件缓存管理难题。如果对你有用,感谢慷慨明星。
演示演示示例代码
哔哩哔哩演示视频感谢三连。
以上就是如何管理某视频剪辑软件中的缓存页面的详细内容,更多关于某视频剪辑软件缓存页面的资料请关注我们其它相关文章!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。