在使用vue + vue-router開發SPA的時候,有沒有遇到過這樣的狀況:當咱們在列表頁和詳情頁之間切換的時候,若是列表頁不作緩存,會致使每次從詳情頁返回時,列表頁都會從新加載。以下圖:html
細心的朋友已經發現了,當從詳情頁返回列表頁的時候,列表頁重載了,這樣的體驗顯然很差,這時咱們能夠對列表頁進行緩存處理。vue
咱們的項目不必定全部頁面都須要作緩存處理,因此這裏介紹兩種按需緩存的方法: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生態系統中的狀態管理庫vuex
。ide
需求分析: 咱們須要一個全局的flag來控制每次進入緩存頁時,數據是否須要重置,正好vuex
能作到。
npm install vuex --save
複製代碼
爲了方便往後維護,能夠建立一個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()
鉤子中重置咱們的頁面數據。
這裏要藉助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