(编辑:jimmy 日期: 2025/1/16 浏览:2)
feb-alive
github地址
体验链接
使用理由
为什么开发feb-laive?
当我们通过Vue开发项目时候,是否会有以下场景需求?
这个场景需求着重强调了缓存,缓存带来的好处是,我上次页面的数据及状态都被保留,无需在从服务器拉取数据,使用户体验大大提高。
尝试用keep-alive实现页面缓存
<keep-alive> <router-view></router-view> </keep-alive>
so easy但是理想很完美,现实很残酷
存在问题
-/a跳到/b,再跳转到/a 的时候,页面中的数据是第一次访问的/a页面,明明是链接跳转,确出现了缓存的效果,而我们期望的是像app一样开启一个新的页面。
举个应用场景
例如浏览文章页面,依次访问3篇文章
当我从/artical/3后退到/artical/2时候,由于组件缓存,此时页面还是文章3的内容,所以必须通过beforeRouteUpdate来重新拉取页面2的数据。(注意此处后退不会触发组件的activated钩子,因为两个路由都渲染同个组件,所以实例会被复用,不会执行reactivateComponent)
如果你想从/artical/3后退到/artical/2时,同时想恢复之前在/artical/2中的一些状态,那么你还需要自己针对/artical/2中的所有状态数据进行存储和恢复。
综上:keep-alive实现的组件级别的缓存和我们想象中的缓存还是有差距的,keep-alive并不能满足我们的需求。
==针对这些问题,所以feb-alive插件诞生了==
由于feb-alive是基于keep-alive实现的,所以我们先简单分析一下keep-alive是如何实现缓存的
export default { name: 'keep-alive', abstract: true, props: { include: patternTypes, exclude: patternTypes, max: [String, Number] }, created () { this.cache = Object.create(null) this.keys = [] }, destroyed () { for (const key in this.cache) { pruneCacheEntry(this.cache, key, this.keys) } }, mounted () { this.$watch('include', val => { pruneCache(this, name => matches(val, name)) }) this.$watch('exclude', val => { pruneCache(this, name => !matches(val, name)) }) }, render () { // 获取默认插槽 const slot = this.$slots.default // 获取第一个组件,也就和官方说明的一样,keep-alive要求同时只有一个子元素被渲染,如果你在其中有 v-for 则不会工作。 const vnode: VNode = getFirstComponentChild(slot) // 判断是否存在组件选项,也就是说只对组件有效,对于普通的元素则直接返回对应的vnode const componentOptions: "htmlcode">created () { // 存储组件缓存 this.cache = Object.create(null) this.keys = [] }由于路由切换并不会销毁keep-alive组件,所以缓存是一直存在的(嵌套路由中,子路由外层的keep-alive情况会不一样,后续会提到)
继续看下keep-alive在缓存的存储和读取的具体实现,先用一个简单的demo来描述keep-alive对于组件的缓存以及恢复缓存的过程
let Foo = { template: '<div class="foo">foo component</div>', name: 'Foo' } let Bar = { template: '<div class="bar">bar component</div>', name: 'Bar' } let gvm = new Vue({ el: '#app', template: ` <div id="#app"> <keep-alive> <component :is="renderCom"></component> </keep-alive> <button @click="change">切换组件</button> </div> `, components: { Foo, Bar }, data: { renderCom: 'Foo' }, methods: { change () { this.renderCom = this.renderCom === 'Foo' "htmlcode">function anonymous( ) { with(this){return _c('div',{attrs:{"id":"#app"}},[_c('keep-alive',[_c(renderCom,