实现全站的页面缓存,前进刷新,返回走缓存,并且能记住上一页的滚动位置,参考了很多技术实现,github上的导航组件实现的原理要么使用的keep-alive,要么参考了keep-alive的源码,但是只用keep-alive没法实现相同path,不同参数展示不同view,这就有点坑了,所以需要结合自己要实现的功能,适当改造keep-alive,为了实现每次前进都能刷新,返回走缓存还能自动定位的功能,文章陆续从以下几个方面展开讲:两套技术方案可选,最后定的技术方案的原因,实现的功能和原理,踩过的坑
方案一:vue的keep-alive组件
具体使用如下:
<keep-alive max="10"> <router-view/> </keep-alive>
为什么这么使用"external nofollow" target="_blank" href="https://cn.vuejs.org/v2/api/#keep-alive">https://cn.vuejs.org/v2/api/#keep-alive)介绍:
<keep-alive> 包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。和 <transition> 相似,<keep-alive> 是一个抽象组件:它自身不会渲染一个 DOM 元素,也不会出现在父组件链中。
当组件在 <keep-alive> 内被切换,它的 activated 和 deactivated 这两个生命周期钩子函数将会被对应执行。主要用于保留组件状态或避免重新渲染。
因为缓存的需要通常出现在切换页面时,所以就需要结合vue-router的router-view来实现
为什么keep-alive能实现缓存?
render () { const slot = this.$slots.default const vnode: VNode = getFirstComponentChild(slot) const componentOptions: "htmlcode">function initComponent (vnode, insertedVnodeQueue) { if (isDef(vnode.data.pendingInsert)) { insertedVnodeQueue.push.apply(insertedVnodeQueue, vnode.data.pendingInsert) vnode.data.pendingInsert = null } vnode.elm = vnode.componentInstance.$el if (isPatchable(vnode)) { invokeCreateHooks(vnode, insertedVnodeQueue) setScope(vnode) } else { // empty component root. // skip all element-related modules except for ref (#3455) registerRef(vnode) // make sure to invoke the insert hook insertedVnodeQueue.push(vnode) } }这里会有 vnode.elm 缓存了 vnode 创建生成的 DOM 节点。所以对于首次渲染而言,除了在 <keep-alive> 中建立缓存,和普通组件渲染没什么区别。从进入到返回的大致执行流程如下
能实现的功能
能够把要缓存的组件渲染的vnode记到cache里边,当返回的时候用缓存里边的dom直接渲染,还有keep-alive组件提供的include 和 exclude属性,可以有条件的缓存想缓存的组件,如果配置了 max 并且缓存的长度超过了这个max的值,还要从缓存中删除第一个
存在的问题
存在的问题是存储vnode节点的key是name,也就是定义路由时组件对应的name,这就会导致同样的path,不同参数的时候打开的是从cache里边拿到的vnode,会渲染出同样的视图出来,但是很多业务场景都是根据参数来显示不同内容,而keep-alive底层并没有对此做扩展,可以看下keep-alive源码
const key: "htmlcode">render () { var vnode = this.$slots.default "htmlcode">//url上新增参数vnk的值 export function genKey() { // const t = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx' const t = 'xxxxxxxx' return t.replace(/[xy]/g, function (c) { const r = Math.random() * 16 | 0 const v = c === 'x' "htmlcode">var scrollBehavior = async (to, from, savedPosition) => { if (savedPosition) { return savedPosition } else { return new Promise((resolve, reject) => { setTimeout(() => { resolve({ x: 0, y: to.meta.savedPosition || 0 }) }, 300) }) } } const router = new VueRouter({ mode: 'history', scrollBehavior, routes: [{ path: '', redirect: '/mobile/home.html', meta: { needMtaReport: true, parentsStyle: { height: '100%', minHeight: '100%' } } }, { name: 'scienceCompetition', path: '/mobile/scienceCompetition.html', component: scienceCompetition }] }总结:
1.单页缓存下js加载解析编译执行的时间缩短了,返回的时候由于走缓存js脚本的占用时间完全可以忽略,从而整体上缩减了页面的加载渲染时间
2. 因为项目以前不是单页,代码里边定义了很多全局变量或者全局事件绑定,改成单页后全局变量的值依然存在,就会导致业务逻辑出现bug,所以使用单页需要注意全局变量或是事件的谨慎使用,具体的踩坑记录在https://www.jb51.net/article/147957.htm
3.通过push进入下一页时,head里边会累加前面页面的静态资源,访问的页面越多,最后的页面挂的静态的资源越多,返回的时候并不会减少已经加载的静态资源,单页缓存是典型的空间换时间的方案,内存的开销比较大,能否对资源动态增减以及内存占用的优化一直在探索中,暂时没有找到很好的解决方法。。。。。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。