背景
在移動端中,頁面跳轉(zhuǎn)之間的緩存是必備的一個需求。
例如:首頁=>列表頁=>詳情頁。
從首頁進入列表頁,列表頁需要刷新,而從詳情頁返回列表頁,列表頁則需要保持頁面緩存。
對于首頁,一般我們都會讓其一直保持緩存的狀態(tài)。
對于詳情頁,不管從哪個入口進入,都會讓其重新刷新。
實現(xiàn)思路
說到頁面緩存,在vue中那就不得不提keep-alive組件了,keep-alive提供了路由緩存功能,本文主要基于它和vuex來實現(xiàn)應(yīng)用里的頁面跳轉(zhuǎn)緩存。
vuex里維護一個數(shù)組cachePages,用以保存當前需要緩存的頁面。
keep-alive 的 includes 設(shè)置為cachePages。
路由meta添加自定義字段 needCachePages或keepAlive,needCachePages 為一個數(shù)組,表示該路由要進入的頁面如果在數(shù)組內(nèi),則緩存該路由,keepAlive則表示無論進入哪個頁面都保持緩存,如app首頁這種。
在路由守衛(wèi)beforeEach里判斷,如果要跳轉(zhuǎn)的路由頁面在當前路由的needCachePages里,則當前路由添加進cachePages里,反之刪除。
具體實現(xiàn)
vuex實現(xiàn)內(nèi)容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
// src/store/modules/app.js export default { state: { // 頁面緩存數(shù)組 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) } } } } |
1
2
3
4
5
6
|
// src/store/getters.js const getters = { cachePages: state => state.app.cachePages } export default getters |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
// 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' // 導(dǎo)出 store 對象 export default new Vuex.Store({ getters, modules: { user, app } }) |
App.vue里,keep-alive的include設(shè)置cachePages
1
2
3
4
5
6
7
8
9
|
<keep-alive :include= "cachePages" > <router-view :key= "$route.fullPath" ></router-view> </keep-alive> computed: { ...mapGetters([ 'cachePages' ]) } |
路由配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
{ 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: '詳情頁' } } |
路由守衛(wèi)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
import Vue from 'vue' import Router from 'vue-router' import store from '@/store' Vue.use(Router) // 導(dǎo)入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) }) // 全局路由守衛(wèi) 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) } // 出現(xiàn)頁面首次緩存失效的情況,猜測是vuex到keep-alive緩存有延遲的原因 //這里使用延遲100毫秒解決 setTimeout(() => { next() }, 100) }) export default router |
還原頁面滾動條位置
此時雖然頁面實現(xiàn)緩存了,但滾動條每次都會重新回到頂部。
對于緩存的頁面,會觸發(fā)activated和deactivated這兩個鉤子,可以利用這兩個鉤子來實現(xiàn)還原滾動條位置。
在頁面離開時,也就是deactivated觸發(fā)時記錄滾動條位置。
在重新回到頁面時,也就是activated觸發(fā)時還原滾動條位置。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
// 創(chuàng)建一個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() } } } |
這里發(fā)現(xiàn)使用deactivated時會因為頁面隱藏過快會導(dǎo)致獲取的節(jié)點滾動條高度為0,所以用beforeRouteLeave。
在需要緩存的頁面中使用
1
2
3
4
5
6
7
|
<script> import { savePosition } from '@/mixins' export default { mixins: [ new savePosition()] } </script> |
如果頁面自定義了滾動容器,此時可以傳入滾動容器id
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<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> |
注意
我的小伙伴經(jīng)常會來問我一個問題,為什么我配置了卻沒有緩存的效果?
這個時候你就需要注意一個問題了,keep-alive的一個關(guān)鍵是路由里的name要和.vue文件里的name保持一致。
如果你的緩存沒有生效,請首先檢查一下兩個name和needCachePages里是否一致。
思考與不足
此方案是我一年多前的做法,現(xiàn)在想來其實還是存在一些不足的,比如每次都需要去配置路由里的needCachePages。
而實際上在移動端中,往往都是在返回上一頁時,上一頁始終保持緩存的狀態(tài),就如開發(fā)小程序時一樣,當我們調(diào)用navigateTo后再返回,頁面始終是緩存的并不需要任何人為的配置。
所以現(xiàn)在的想法是,在vue中提供一個全局的跳轉(zhuǎn)api,只要調(diào)用該api就把當前頁面緩存,如果需要刷新操作,可以像小程序里的onShow一樣在activated里執(zhí)行你的邏輯。
到此這篇關(guān)于vue移動端項目中如何實現(xiàn)頁面緩存的示例代碼的文章就介紹到這了,更多相關(guān)vue 頁面緩存內(nèi)容請搜索服務(wù)器之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持服務(wù)器之家!
原文鏈接:https://juejin.cn/post/6944962862410367006