vue中使用keepAlive缓存页面及记忆上次浏览位置,并刷新页面

    平时业务开发中,列表页面是很常见的,而列表页面有一个很常见的需求就是要缓存整个页面,而且还要记住列表的滚动位置,当点击某个列表项进入详情页,再返回到列表页面的时候,要能够回到原来的滚动位置。

上面的需求我相信业务开发人员基本都碰到过,那么在 vue 中,这个需求要怎么实现呢,这票文章就来说一下,在实现这个功能的过程中,还有几个需要注意的点后面也会说到。

一,用 keep-alive 实现路由缓存
在 vue 项目中,要想实现缓存功能,有一个很简单方便的方法就是使用 keep-alive 组件,keep-alive 可以实现组件或路由级的缓存,这里就以路由缓存为例来说下。

1,在 App.vue 中的路由组件 router-view 上加上 keep-alive
像页面缓存这种功能,在一个应用中可能会有的页面不需要,而有的页面又需要,所以就需要将这功能放在全局,并做成可配置的,这样才能进行灵活配置。

而整个项目的所有页面其实都是挂在 app 这个节点下,通过 router-view 加载和显示出来的。所以我们在 app.vue 这个文件这里给 router-view 加上 keep-alive。

    <!--缓存想要缓存的页面,实现后退不刷新-->
    <!--加上v-if的判断,可以自定义想要缓存的组件,自定义在router里面-->
      <keep-alive>
        <router-view v-if="$route.meta.keepAlive"></router-view>
      </keep-alive>
      <router-view v-if="!$route.meta.keepAlive"></router-view>
  </div>

注意点一:用 keep-alive 包裹需要缓存的路由,但是判断条件不要写在 keep-alive 上,需要写在 router-view 上,不然会没有作用
注意点二:当 router-view 有 transition 过渡动画时的写法。
如果需要自定义路由的切换过渡动画,那么就需要在 router-view 上加上 transition 组件,当加上 transition 之后,HTML 层级就达到了三级,然后 transition ,keep-alive ,router-view ,v-if 这几者之间可以有多种不同的组合,在尝试了各种不同的组合之后,我发现只有一种写法可以达到缓存效果,但也有一点小瑕疵,那就是缓存的页面不会触发过渡动画,这也是一个比较遗憾的地方。代码如下:

<div id="app" class="main-app">
    <!--缓存想要缓存的页面,实现后退不刷新-->
    <!--加上v-if的判断,可以自定义想要缓存的组件,自定义在router里面-->
    <!--keepAlive 的路由不会触发 transition,参见 					   https://github.com/vuejs/vue-router/issues/811 -->
    <transition name='fade' mode="out-in">
      <keep-alive>
        <router-view v-if="$route.meta.keepAlive"></router-view>
      </keep-alive>
    </transition>
    
    <transition name='fade' mode="out-in">
      <router-view v-if="!$route.meta.keepAlive"></router-view>
    </transition>
  </div>

2,在 router.js 中为需要缓存的路由设置缓存参数
在上面的代码中,有一个判断条件 $route.meta.keepAlive ,这个条件就是用来区分该路由是否需要缓存的,这个条件需要写在 router.js 路由表文件中。

{path: ‘/msg’, name: ‘Message’, meta: {keepAlive: true}, component: Message},
如上,就是在需要缓存的路由里面,给该路由加上 meta 元信息,在里面设置是否需要缓存即可。

二,记录页面滚动位置
要记住滚动位置,有多种实现方式,然而最简单,最便捷的方式就是在路由表中加上 scrollBehavior,这也是官方推荐的方式。

new Router({
    mode: 'history',
    scrollBehavior (to, from, savedPosition) {
      if (savedPosition) { //如果savedPosition存在,滚动条会自动跳到记录的值的地方
        return savedPosition
      } else {
        return {x: 0, y: 0}//savedPosition也是一个记录x轴和y轴位置的对象
      }
    },
    routes: []
 })

只要在 router.js 中加入如上的 scrollBehavior 那段代码,就可以实现 router-view 的记录滚动位置的功能了,这功能是 vue 内封装的,用起来简单方便。

做完上面两步就可以实现简单的页面缓存和记住滚动位置的功能了,但是真正用起来却发现仅仅是这样还是不够的。按照上面的代码缓存功能是实现了,但是你会发现,被缓存的页面不会再重新请求数据了(没有做下拉刷新等操作的时候),这样其实是不太好的,其实我们大多数时候需要的是从列表详情页回到列表的时候不刷新,但是从其他页面进入列表页的时候需要重新请求数据。那么要怎么实现这么个功能呢?

三,详情页返回列表页不刷新,其他页面进入列表页刷新
在前面的代码中,我们实现了路由级的页面缓存,也记住了页面滚动位置,但同时也发现被缓存的页面不会再重新请求数据,这样也是不行的,我们现在就来解决这个问题。

要解决这个问题,首先需要用到 vue 的生命周期和路由钩子的相关知识点。因为我们这里使用了 keep-alive 组件来做缓存,所以生命周期等钩子函数的执行顺序就有了两种情况。

不使用 keep-alive 时
beforeRouteEnter --> created --> mounted --> destroyed
使用 keep-alive 时
beforeRouteEnter --> created --> mounted --> activated --> deactivated
再次进入缓存的页面,只会触发beforeRouteEnter -->activated --> deactivated 。created和mounted不会再执行。
基于上面的两点,我们就可以解决被缓存的页面一直不刷新的问题了。

1,在路由的 mate 中添加一个变量,表示是否需要刷新
{path: ‘/msg’, name: ‘Message’, meta: {keepAlive: true, isNeedRefresh: true}, component: Message},
2,在页面组件的 data 中定义一个变量,表示是否是第一次进入该页面

data () {
      return {
        isFirstEnter: false,
      }
    },

3,在相关的钩子函数中判断是否是第一次进入页面,是否需要重新加载数据

beforeRouteEnter (to, from, next) {
      // 利用路由元信息中的 meta 字段设置变量,方便在各个位置获取。这就是为什么在 meta 中定义 isNeedRefresh。
      // 当从详情页返回时,将 isNeedRefresh 设为 false,表示不刷新数据
      if (from.name === 'MsgDetail') {
        to.meta.isNeedRefresh = false
      }
      next()
    },
    mounted () {
      // 只有第一次进入或者刷新页面后才会执行此钩子函数,使用keep-alive后(2+次)进入不会再执行此钩子函数
      // isFirstEnter 用来标记是否第一次进入该页面,以防止用户在详情页手动刷新页面,回到该页面后不再请求数据
      this.isFirstEnter = true
    },
    activated () {
      if (this.$route.meta.isNeedRefresh || this.isFirstEnter) {
        // 如果 isNeedRefresh 是 true,表明需要获取新数据,否则就不再请求,直接使用缓存的数据
        this.queryListData()
      }
      // 恢复成默认的 false,避免 isFirstEnter 一直是 true,导致重复获取数据
      this.isFirstEnter = false
      // 恢复成默认的 true,避免 isNeedRefresh 一直是 false,导致下次无法获取数据
      this.$route.meta.isNeedRefresh = true
    },

这里面的判断逻辑有点小绕,需要好好理解下。完成上面的代码也就可以实现从详情页返回不刷新,自动滚动到原先的位置,而从其他页面进入则重新获取数据的需求。

四、返回记录位置的页面需要进行刷新数据
凡是被keep-alive包裹住的页面都会被缓存,如果想刷新内容要启用activated函数,用法同created,activated只有在被keep-alive包裹时会触发,activated函数一进入页面就触发

activated(){
    //返回页面时刷新数据,需要重新请求的写在这里
    this.getParkList();
  },

五,额外需要注意的地方(没测)
1,keep-alive 与 lazyload 同时使用时要注意
这个问题是我偶尔发现的,有时候会发现使用了 lazyload 加载的图片有时会显示不正确,刷新下就又正常了。这其实是 lazyload 导致的问题,当单独操作一二个数据添加或删除的时候,lazyload 会导致图片的显示位置错乱,我还没找到很好的处理办法,只有先暂时去掉 lazyload。如果有更好的处理方式,烦请告知。

2,要注意页面布局,不要限制页面滚动位置
在使用了 keep-alive 做路由级缓存的页面,不要限定页面的滚动位置,让页面能够自然滚动就行,不要给滚动区域设置固定高度。设置了固定高度的话,记录滚动位置的功能就会不起作用,缓存功能是还在,但是并不会自动记住滚动位置。

  • 5
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
根据引用的代码,你可以使用全局的 `excludes` 变量来控制 keep-alive缓存。当你需要清除缓存刷新页面时,只需要调用 `resetKeepAliveCache` 函数,并传入需要恢复缓存的组件名。这会从 `excludes.value` 数组移除该组件名,从而清除缓存。 另外,根据引用的代码,你可以通过设置 `keepAlive` 属性来决定是否缓存组件。如果 `keepAlive` 为 `true`,则会使用 `<keep-alive>` 包裹组件,实现缓存的效果。如果 `keepAlive` 为 `false`,则不会包裹组件,不会进行缓存。 需要注意的是,根据引用的代码,Vue 3 对于 `cache` 数组的操作权限仅限于开发环境。因此,在生产环境,对于 `cache` 数组的操作可能无效。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [Vue 适时清理 keepalive 缓存方案](https://blog.csdn.net/web22050702/article/details/126431957)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] - *2* [keep-alive清除缓存](https://blog.csdn.net/HuaCHen_SHan/article/details/125541945)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值