首页 > 语言 > JavaScript > 正文

vue spa应用中的路由缓存问题与解决方案

2024-05-06 15:38:34
字体:
来源:转载
供稿:网友

单页面应用中的路由缓存问题

通常我们在进行页面前后退时,浏览器通常会帮我们记录下之前滚动的位置,这使得我们不会在每次后退的时候都丢失之前的浏览器记录定位。但是在现在愈发流行的SPA(single page application 单页面应用)中,当我们从父级页面打开子级页面,或者从列表页面进入详情页面,此时如果回退页面,会发现之前我们浏览的滚动记录没有了,页面被置顶到了最顶部,仿佛是第一次进入这个页面一样。这是因为在spa页面中的url与路由容器页面所对应,当页面路径与其发生不匹配时,该页面组件就会被卸载,再次进入页面时,整个组件的生命周期就会完全重新走一遍,包括一些数据的请求与渲染,所以之前的滚动位置和渲染的数据内容也都完全被重置了。

vue中的解决方式

vue.js最贴心的一点就是提供了非常多便捷的API,为开发者考虑到很多的应用场景。在vue中,如果想缓存路由,我们可以直接使用内置的keep-alive组件,当keep-alive包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。

内置组件keep alive

keep-alive是Vue.js的一个内置组件。它主要用于保留组件状态或避免重新渲染。

使用方法如下:

<keep-alive :include="['a', 'b']"> <component :is="view"></component></keep-alive>

keep-alive组件会去匹配name名称为 'a', 'b' 的子组件,在匹配到以后会帮助组件缓存优化该项组件,以达到组件不会被销毁的目的。

实现原理

先简要看下keep-alive组件内部实现代码,具体代码可以见Vue GitHub

created () { this.cache = Object.create(null) this.keys = []}

在created生命周期中会用Object.create方法创建一个cache对象,用来作为缓存容器,保存vnode节点。Tip: Object.create(null)创建的对象没有原型链更加纯净

render () { const slot = this.$slots.default const vnode: VNode = getFirstComponentChild(slot) const componentOptions: ?VNodeComponentOptions = vnode && vnode.componentOptions if (componentOptions) {  // check pattern 检查匹配是否为缓存组件,主要根据include传入的name来对应  const name: ?string = getComponentName(componentOptions)  const { include, exclude } = this  if (   // not included  该判断中判断不被匹配,则直接返回当前的vnode(虚拟dom)  (include && (!name || !matches(include, name))) ||  // excluded  (exclude && name && matches(exclude, name))  ) {   return vnode  }  const { cache, keys } = this  const key: ?string = vnode.key == null   // same constructor may get registered as different local components   // so cid alone is not enough (#3269)   ? componentOptions.Ctor.cid + (componentOptions.tag ? `::${componentOptions.tag}` : '')   : vnode.key  if (cache[key]) {   //查看cache对象中已经缓存了该组件,则vnode直接使用缓存中的组件实例   vnode.componentInstance = cache[key].componentInstance   // make current key freshest    remove(keys, key)   keys.push(key)  } else {   //未缓存的则缓存实例   cache[key] = vnode   keys.push(key)   // prune oldest entry   if (this.max && keys.length > parseInt(this.max)) {    pruneCacheEntry(cache, keys[0], keys, this._vnode)   }  }  vnode.data.keepAlive = true } return vnode || (slot && slot[0])}            
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表

图片精选