vue+vuerouter+vuex通过keepalive控制页面缓存
需求:
vue+vuerouter+vuex通过keepalive控制页面缓存,有时候我们从列表页A进入详情页的时候,而详情页里面也有一个列表页B,当我们从详情页进入列表页B时,希望详情页缓存下来,当从列表页B返回到详情页时,我们需要详情页,不需要重新请求渲染页面,并且当前页面的滚动位置回到原来的位置,再继续返回到列表页A时,我们需要详情页不被缓存
目录结构
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
| project │ └───src │ │ | └───mixins | | scroll-position.js | | │ └───store | | | index.js | | | │ | └───common │ | index.js | | │ └───common │ | tools.js | | | └───router | | index.js | | | └───views | | list-a.vue | | detail.vue | | list-b.vue | | | └───App.vue
|
1.编写保存滚动位置方法
在目录下新建一个mixins文件夹,在目录下新建一个scroll-position.js,用户保存离开页面的滚动位置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| const scrollPosition = { data() { return { } }, activated() { if (this.$route.meta.keepAlive) { let pageName = this.$route.name; let pagePositions = this.$store.state.CommonModule.pagePositions; let res = pagePositions.find(v => v.name === pageName); if (res && res.position > 0) { this.$nextTick(function () { document.documentElement.scrollTop = document.body.scrollTop = res.position || 0; }); } } }, computed: {} };
export default scrollPosition;
|
2.编写状态管理
在目录下新建一个store文件夹,在store文件夹下面新建一个index.js,在store文件夹下面新建一个common文件夹,在common文件夹下面新建一个index.js
/common/tools.js
1 2 3 4 5 6 7 8
|
export const getRawType = (value) => { return Object.prototype.toString.call(value).slice(8, -1) };
|
/store/common/tools.js
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 58 59 60 61 62 63 64
| import {getRawType} from '../../common/tools';
const state = { pagePositions: [], cachedPages: [] };
const mutations = { SAVE_POSITION(state, data) { let pagePositions = state.pagePositions; let key = -1; pagePositions.find((v, k) => { if (v.name === data.name) { key = k; return v } }); key >= 0 ? pagePositions[key] = data : pagePositions.push(data); state.pagePositions = pagePositions; }, SET_CACHED_PAGE(state, pageName) { if (getRawType(pageName) === 'Array') { state.cachedPages = pageName } else { let cached_pages = state.cachedPages; let res = cached_pages.filter(cachedPage => cachedPage === `page-${pageName}`); if (res.length <= 0) { cached_pages.push(`page-${pageName}`); state.cachedPages = cached_pages; } } }, REMOVE_CACHED_PAGE(state, pageName) { let cached_pages = state.cachedPages; let index = cached_pages.findIndex(cachedPage => cachedPage === `page-${pageName}`) if (index >= 0) { cached_pages.splice(index, 1); state.cachedPages = cached_pages } } };
const getters = { };
const actions = { savePosition({commit}, data) { commit('SAVE_POSITION', data) }, setCachedPage({commit}, pageName) { commit('SET_CACHED_PAGE', pageName) }, removeCachedPage({commit}, pageName) { commit('REMOVE_CACHED_PAGE', pageName) } };
export default { namespace: true, state, mutations, getters, actions }
|
/store/index.js
1 2 3 4 5 6 7 8 9 10 11 12
| import Vue from 'vue' import Vuex from 'vuex' import CommonModule from './common'
Vue.use(Vuex);
export default new Vuex.Store({ strict: process.env.NODE_ENV !== 'production', modules: { CommonModule } })
|
3.对特定页面编写缓存方法
app.vue
利用keeplive的include属性,详情可看https://cn.vuejs.org/v2/api/#keep-alive
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
| <template> <div id="app"> <div class="app-container"> <keep-alive :include="cachedPages"> <router-view/> </keep-alive> </div> </div> </template>
<script type="text/ecmascript-6"> import {mapState} from 'vuex';
export default { data() { return {} }, components: { }, created() { }, computed: { ...mapState({ cachedPages: state => state.CommonModule.cachedPages }) } } </script> <style lang="less"> </style>
|
/views/lista.vue
在详情页面加入beforeRouteLeave生命周期,
缓存的页面再次被激活的时候会触发activated生命周期,页面被缓存离开的时候会触发deactivated生命周期
/views/lista.vue
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
| <template> <div> i am list a </div> </template>
<script type="text/ecmascript-6"> import scrollPosition from "../mixins/scroll-position";
export default { name: 'page-list-a', mixins: [scrollPosition], data() { return { } }, beforeRouteLeave(to, from, next) { if (['detail'].some(name => name === to.name)) { from.meta.keepAlive = true; this.$store.dispatch('setCachedPage', from.name).then(() => { next() }); } else { from.meta.keepAlive = false; this.$store.dispatch('removeCachedPage', from.name).then(() => { next(); }); } } }; </script> <style lang="less" scoped> </style>
|
/views/detail.vue
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
| <template> <div> i am detail </div> </template>
<script type="text/ecmascript-6"> export default { name: 'page-detail', data() { return { } }, beforeRouteLeave(to, from, next) { if (['list-a'].some(name => name === to.name)) { from.meta.keepAlive = true; this.$store.dispatch('setCachedPage', from.name).then(() => { next() }); } else { from.meta.keepAlive = false; this.$store.dispatch('removeCachedPage', from.name).then(() => { next(); }); } } }; </script> <style lang="less" scoped> </style>
|
list-b.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <template> <div> i am list b </div> </template>
<script type="text/ecmascript-6">
export default { name: 'page-list-b', data() { } </script> <style lang="less" scoped> </style>
|
/router/index.js
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
| import Vue from 'vue' import VueRouter from 'vue-router'
const originalPush = VueRouter.prototype.push; VueRouter.prototype.push = function push(location, onResolve, onReject) { if (onResolve || onReject) return originalPush.call(this, location, onResolve, onReject); return originalPush.call(this, location).catch(err => err) }; Vue.use(VueRouter);
const routes = [ { path: '/list-a', name: 'list-a', meta: { title: '列表页A' }, component: () => import ('../views/list-a') }, { path: '/detail', name: 'detail', meta: { title: '详情页', keepAlive: true }, component: () => import ('../views/detail') }, { path: '/list-b', name: 'list-b', meta: { title: '列表页B' }, component: () => import ('../views/list-b') } ];
const router = new VueRouter({ mode: 'history', routes });
export default router
|
最后更新时间: