vue.js

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > vue.js > 使用router.meta.keepAlive对页面进行缓存

vue如何使用router.meta.keepAlive对页面进行缓存

作者:doit_damao

这篇文章主要介绍了vue如何使用router.meta.keepAlive对页面进行缓存问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

使用router.meta.keepAlive对页面进行缓存

需求:

1. 从stockList页面到stockInfo页面,从stockInfo页面返回stockList,缓存stockList页面           

2. 从其他页面进入到stockList页面,则不缓存stockList页面

路由配置文件中:

{
  path: '/stockSelectionAndDiagnosticStocks',
  name: 'stockSelectionAndDiagnosticStocks',
  component: stockSelectionAndDiagnosticStocks,
  redirect: '/stockSelectionAndDiagnosticStocks/stockList',
  children: [
    {
      path: '/stockSelectionAndDiagnosticStocks/stockList',
      name: 'stockList',
      component: stockList,
      // 此处设置的原因:保证第一次从stockList进入到stockInfo中是缓存了的
      meta: { keepAlive: true }
    },
    {
      path: '/stockSelectionAndDiagnosticStocks/stockInfo',
      name: 'stockInfo',
      component: stockInfo
    }
  ]
}

App.vue中:

<div id="app">
  <keep-alive>
    <router-view v-if="$route.meta.keepAlive"></router-view>
  </keep-alive>
  <router-view v-if="!$route.meta.keepAlive"></router-view>
</div>

stockList.vue中:

beforeRouteLeave (to, from, next) {
  // 从列表页去到别的页面,如果不是详情页,则不缓存列表页
  if (to.name !== 'stockInfo') {
    this.$route.meta.keepAlive = false
  } else {
    this.$route.meta.keepAlive = true
  }
  next()
}

*** 增加需求:从stockInfo页面通过“特殊的”点击事件回到stockList,stockList页面的列表需要按照字段更新 *** stockInfo.vue中:(其中setStore、getStore是封装的sessionStorage)

clickHistoryItem (val) {
  setStore('searchName', val)
  this.$router.push({ name: 'stockList' })
}

stockList.vue中:

// 只有当缓存的情况写才触发这两个钩子函数
activated () {
  if (getStore('searchName')) {
    this.pageIndex = 1
    this.searchStockFirstStep(getStore('searchName'))
  }
},
deactivated () {
  removeStore('searchName')
}

使用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>

如果需要自定义路由的切换过渡动画,那么就需要在 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 做路由级缓存的页面,不要限定页面的滚动位置,让页面能够自然滚动就行,不要给滚动区域设置固定高度。设置了固定高度的话,记录滚动位置的功能就会不起作用,缓存功能是还在,但是并不会自动记住滚动位置。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文