keep-alive + vuex 讓緩存的頁面靈活起來

引入

在使用vue + vue-router開發SPA的時候,有沒有遇到過這樣的狀況:當咱們在列表頁和詳情頁之間切換的時候,若是列表頁不作緩存,會致使每次從詳情頁返回時,列表頁都會從新加載。以下圖:html

細心的朋友已經發現了,當從詳情頁返回列表頁的時候,列表頁重載了,這樣的體驗顯然很差,這時咱們能夠對列表頁進行緩存處理。vue

keep-alive實現頁面緩存

咱們的項目不必定全部頁面都須要作緩存處理,因此這裏介紹兩種按需緩存的方法:vue-router

方法一:

首先在定義路由的時候配置 meta 字段,自定義一個KeepAlive字段做爲該頁面是否緩存的標記:vuex

routes:[{
    path: '/search',
    name: 'search',
    component: search,
    meta: {
        title: '搜索列表頁',
        keepAlive: true // 標記列表頁須要被緩存
    }
},
{
    path: '/detail',
    name: 'detail',
    component: detail,
    meta: {
        title: '詳情頁',
        // 詳情頁不須要作緩存,因此不加keepAlive標記
    }
}]
複製代碼

因爲<keep-alive>組件不支持v-if指令,因此咱們在App.vue中採用兩個<router-view>的寫法,經過當前路由的keepAlive字段來判斷是否對頁面進行緩存:npm

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

方法二

使用<keep-alive>提供的 exclude 或者 include 選項,此處咱們使用 exclude ,在App.vue中:api

<div id="app">
    <keep-alive exclude="detail">
        <router-view />
    </keep-alive>
</div>
複製代碼

須要注意的是,必定要給頁面組件加上相應的name,例如在detail.vue中:緩存

<script>
export default {
    name: 'detail', // 這個name要和keep-alive中的exclude選項值一致
    ...
}
</script>
複製代碼

這麼寫就表明了在項目中除了name爲detail的頁面組件外,其他頁面都將進行緩存。bash

特殊狀況優化:

若是詳情頁也作了keep-alive,那麼列表頁和詳情頁切換時,滾動位置可能會相互影響,這時須要在 Router 實例中提供一個 scrollBehavior 方法:app

export default new Router({
    scrollBehavior (to, from, savedPosition) {
    	if (savedPosition) {
    		return savedPosition
    	} else {
    		return { x: 0, y: 0 }
    	}
    },
    routes: [...],
})
複製代碼

效果展現

效果看似很不錯,實現了列表頁的緩存。但這其實並不靈活,好比返回首頁再進入這個搜索頁的時候,因爲沒作任何處理,因此這個搜索頁它仍處於以前的狀態:

然而,我但願凡是從首頁進入搜索頁,頁面數據都須要重置回初始狀態,有沒有什麼方能夠靈活控制頁面數據是否須要重置呢?這時個人腦海裏浮現了vue生態系統中的狀態管理庫vuexide

藉助vuex使頁面更靈活

需求分析: 咱們須要一個全局的flag來控制每次進入緩存頁時,數據是否須要重置,正好vuex能作到。

vuex搞起來

安裝

npm install vuex --save
複製代碼

配置vuex

爲了方便往後維護,能夠建立一個store目錄專門存放vuex的模塊代碼,目錄結構參考下圖:

state.js:

const state = {
    refreshSearch: true // 標記是否刷新搜索頁
}

export default state
複製代碼

mutation.js

const matutaions = {
    setRefreshSearch(state, flag) {
        state.refreshSearch = flag
    }
}
  
export default matutaions
複製代碼

index.js

import Vue from 'vue'
import Vuex from 'vuex'
import state from './state'
import mutations from './mutations'

Vue.use(Vuex)

export default new Vuex.Store({
    state,
    mutations
})
複製代碼

在入口文件main.js中:

import store from './store' //這裏是指向store目錄中的index.js
new Vue({
    router,
    store,
    render: h => h(App)
}).$mount('#app')
複製代碼

這樣,咱們就至關於用vuex建立了一個用來判斷頁面是否須要重置的標記了。

隨心所欲地重置你的緩存頁中的數據

在哪裏重置

keep-alive的組件有個特有的生命週期鉤子activated()activated()會在keep-alive的組件每次激活時調用,而created()只有建立的時候會被調用一次,再次激活就不會被調用了。因此這裏咱們須要在activated()鉤子中重置咱們的頁面數據。

在activated()中想重置就重置

這裏要藉助vuex中的refreshSearch標記來判斷是否須要重置

search.vue:(這個是須要緩存的頁面)

<script>
import {mapState, mapMutations} from 'vuex' //vuex提供的映射函數,用來簡化代碼的
export default {
    activated() {
        if (this.refreshSearch) {
            // 若爲true,則執行重置頁面等相關操做
            this.fetchData();
        } else {
            this.reset(true);
        }
    },
    methods:{
        fetchData() {
            // 獲取頁面數據
        },
        ...mapMutations({
            reset: 'setRefreshSearch' // 將 `this.reset()` 映射爲 `this.$store.commit('setRefreshSearch')`
        })
    },
    computed: {
        ...mapState([
            'refreshSearch' // 映射 this.refreshSearch 爲 this.$store.state.refreshSearch
        ]),
    }
}
</script>
複製代碼

當咱們從搜索頁去詳情頁時,但願搜索頁緩存,只須要把標記設爲false:

methods: {
    goDetail() {
        this.reset(false) // 這樣返回搜索頁的時候,搜索頁就不會重置數據了
        this.$router.push({path: '/detail'})
    },
    ...mapMutations({
        reset: 'setRefreshSearch'
    })
}

複製代碼

當咱們從首頁去搜索頁時,但願搜索頁數據重置,只需把標記設爲true:

methods: {
    goSearch() {
        this.reset(true) // 這樣去搜索頁時數據就會被重置了
        this.$router.push({path: '/search'})
    },
    ...mapMutations({
        reset: 'setRefreshSearch'
    })
}

複製代碼

效果預覽

總結

本文介紹了按需使用keep-alive,以及藉助vuex來控制keep-alive的組件頁面的數據是否須要重置刷新,但願對你們有幫助。

附送相關知識傳送門:
vue內置組件keep-alive

vue-router滾動行爲

生命週期鉤子activated

vuex狀態管理庫

相關文章
相關標籤/搜索