vue移動端項目中如何實現頁面緩存的示例代碼

背景

在移動端中,頁面跳轉之間的緩存是必備的一個需求。

例如:首頁=>列表頁=>詳情頁。

從首頁進入列表頁,列表頁需要刷新,而從詳情頁返回列表頁,列表頁則需要保持頁面緩存。

對於首頁,一般我們都會讓其一直保持緩存的狀態。

對於詳情頁,不管從哪個入口進入,都會讓其重新刷新。

實現思路

說到頁面緩存,在vue中那就不得不提keep-alive組件瞭,keep-alive提供瞭路由緩存功能,本文主要基於它和vuex來實現應用裡的頁面跳轉緩存。

vuex裡維護一個數組cachePages,用以保存當前需要緩存的頁面。
keep-alive 的 includes 設置為cachePages。
路由meta添加自定義字段 needCachePages或keepAlive,needCachePages 為一個數組,表示該路由要進入的頁面如果在數組內,則緩存該路由,keepAlive則表示無論進入哪個頁面都保持緩存,如app首頁這種。
在路由守衛beforeEach裡判斷,如果要跳轉的路由頁面在當前路由的needCachePages裡,則當前路由添加進cachePages裡,反之刪除。

具體實現

vuex實現內容

// src/store/modules/app.js

export default {
 state: {
  // 頁面緩存數組
  cachePages: []
 },
 
 mutations: {
  // 添加緩存頁面
  ADD_CACHE_PAGE(state, page) {
   if (!state.cachePages.includes(page)) {
    state.cachePages.push(page)
   }
  },
  
  // 刪除緩存頁面
  REMOVE_CACHE_PAGE(state, page) {
   if (state.cachePages.includes(page)) {
    state.cachePages.splice(state.cachePages.indexOf(page), 1)
   }
  }
 }
}


// src/store/getters.js

const getters = {
 cachePages: state => state.app.cachePages
}
export default getters

// src/store/index.js

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)

import user from './modules/user'
import app from './modules/app'
import getters from './getters'

// 導出 store 對象
export default new Vuex.Store({
 getters,
 modules: {
  user,
  app
 }
})

App.vue裡,keep-alive的include設置cachePages

<keep-alive :include="cachePages">
 <router-view :key="$route.fullPath"></router-view>
</keep-alive>

computed: {
 ...mapGetters([
  'cachePages'
 ])
}

路由配置

{
  path: '/home',
  name: 'Home',
  component: () => import('@/views/tabbar/Home'),
  meta: {
   title: '首頁',
   keepAlive: true
  }
},
{
  path: '/list',
  name: 'List',
  component: () => import('@/views/List'),
  meta: {
   title: '列表頁',
   needCachePages: ['ListDetail']
  }
},
{
  path: '/list-detail',
  name: 'ListDetail',
  component: () => import('@/views/Detail'),
  meta: {
   title: '詳情頁'
  }
}

路由守衛

import Vue from 'vue'
import Router from 'vue-router'
import store from '@/store'
Vue.use(Router)

// 導入modules文件夾裡的所有路由
const files = require.context('./modules', false, /\.js$/)
let modules = []
files.keys().forEach(key => {
 modules = modules.concat(files(key).default)
})

// 路由
const routes = [
 {
  path: '/',
  redirect: '/home',
 },
 ...modules
]

const router = new Router({
 mode: 'hash',
 routes: routes
})


function isKeepAlive(route) {
 if (route.meta && route.meta.keepAlive) {
  store.commit('ADD_CACHE_PAGE', route.name)
 }
 if (route.children) {
  route.children.forEach(child => {
   isKeepAlive(child)
  })
 }
}

routes.forEach(item => {
 isKeepAlive(item)
})

// 全局路由守衛
router.beforeEach((to, from, next) => {
 if (from.meta.needCachePages && from.meta.needCachePages.includes(to.name)) {
  store.commit('ADD_CACHE_PAGE', from.name)
 } else if (from.meta.needCachePages) {
  store.commit('REMOVE_CACHE_PAGE', from.name)
 }
 // 出現頁面首次緩存失效的情況,猜測是vuex到keep-alive緩存有延遲的原因
 //這裡使用延遲100毫秒解決
 setTimeout(() => {
  next()
 }, 100)
})

export default router

還原頁面滾動條位置

此時雖然頁面實現緩存瞭,但滾動條每次都會重新回到頂部。

對於緩存的頁面,會觸發activated和deactivated這兩個鉤子,可以利用這兩個鉤子來實現還原滾動條位置。

在頁面離開時,也就是deactivated觸發時記錄滾動條位置。

在重新回到頁面時,也就是activated觸發時還原滾動條位置。

// 創建一個mixin
// src/mixins/index.js

export const savePosition = (scrollId = 'app') => {
 return {
  data() {
   return {
    myScrollTop: 0
   }
  },
  
  activated() {
   const target = document.getElementById(scrollId)
   target && target.scrollTop = this.myScrollTop
  },
  
  beforeRouteLeave(to, from, next) {
   const target = document.getElementById(scrollId)
   this.myScrollTop = target.scrollTop || 0
   next()
  }
 }
}

這裡發現使用deactivated時會因為頁面隱藏過快會導致獲取的節點滾動條高度為0,所以用beforeRouteLeave。

在需要緩存的頁面中使用

<script>
import { savePosition } from '@/mixins'

export default {
 mixins: [new savePosition()]
}
</script>

如果頁面自定義瞭滾動容器,此時可以傳入滾動容器id

<template>
  <div id="scroll-container" style="height: 100vh; overflow-y: scroll;">

  </div>
</template>

<script>
import { savePosition } from '@/mixins'

export default {
 mixins: [new savePosition('scroll-container')]
}
</script>

註意

我的小夥伴經常會來問我一個問題,為什麼我配置瞭卻沒有緩存的效果?

這個時候你就需要註意一個問題瞭,keep-alive的一個關鍵是路由裡的name要和.vue文件裡的name保持一致。

如果你的緩存沒有生效,請首先檢查一下兩個name和needCachePages裡是否一致。

思考與不足

此方案是我一年多前的做法,現在想來其實還是存在一些不足的,比如每次都需要去配置路由裡的needCachePages。

而實際上在移動端中,往往都是在返回上一頁時,上一頁始終保持緩存的狀態,就如開發小程序時一樣,當我們調用navigateTo後再返回,頁面始終是緩存的並不需要任何人為的配置。

所以現在的想法是,在vue中提供一個全局的跳轉api,隻要調用該api就把當前頁面緩存,如果需要刷新操作,可以像小程序裡的onShow一樣在activated裡執行你的邏輯。

到此這篇關於vue移動端項目中如何實現頁面緩存的示例代碼的文章就介紹到這瞭,更多相關vue 頁面緩存內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!