本文章存在缺陷,最後也沒能夠完善這個方案,大家看看就好。不過用這位大牛寫的專案可以解決問題,配置也特別簡單vue-navigaition。
最近在用vue嘗試著做移動端的專案。希望實現前進重新整理、後退不重新整理的效果。即載入過的介面能快取起來(返回不用重新載入),關閉的介面能被銷燬掉(再進入時重新載入)。例如對a->b->c 前進(b,c)重新整理,c->b->a 後退(b,a)不重新整理。
由於keep-alive
會把所有載入過的介面都快取起來,沒法實現返回時將介面銷燬掉,導致再進入時沒有重新載入這個介面。於是首先想到的方案是在點選介面上返回按鈕的時候,呼叫this.$destroy(true)
來將介面銷燬掉。但是在移動端 android裝置上會有物理返回鍵,如果通過物理返回鍵返回的話,就沒法處理了。雖然可以重寫android的返回事件,來呼叫js的方法,但是呼叫的是js的全域性方法,沒法具體讓在最上層的那個介面銷燬掉。
於是就需要另闢蹊徑了。還好這篇文章給了我啟發vue-router 之 keep-alive,多謝作者的分享。
要是能夠知道路由是前進還是後退就好了,這樣的話我就能在後退的時候讓from
路由的keepAlive
置為false
,to
路由的keepAlive
置為ture
,就能在再次前進時,重新載入之前這個keepAlive
被置為false
的路由了。
廢話不多說了,這裡模擬有三個介面 login
到server
到main
。
首先我給這三個介面路由的path
設定了嚴格的層級關係 ,並設定keepAlive
都是true
,預設都是需要快取。
const router = new Router({
routes: [
{
path: '/',
redirect: '/login'
},
{
path: '/login',
component: Login,
meta: {
keepAlive: true
}
},
{
path: '/login/server',
component: ServerList,
meta: {
keepAlive: true
}
},
{
path: '/login/server/main',
component: Main,
meta: {
keepAlive: true
}
}
]
})
複製程式碼
由於這三個介面path的層級不同,我就能通過beforeEach
這個鉤子判斷出什麼時候是後退了。在後退時將from
路由的keepAlive
置為false
,to
路由的keepAlive
置為ture
。
router.beforeEach((to, from, next) => {
const toDepth = to.path.split('/').length
const fromDepth = from.path.split('/').length
if (toDepth < fromDepth) {
console.log('後退。。。')
from.meta.keepAlive = false
to.meta.keepAlive = true
}
next()
})
複製程式碼
最後需要快取的介面用keep-alive
包起來,就能實現時前進重新整理,後退時不重新整理的效果了。
<keep-alive>
<router-view v-if="$route.meta.keepAlive">
<!-- 這裡是會被快取的檢視元件 -->
</router-view>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive">
<!-- 這裡是不被快取的檢視元件 -->
</router-view>
複製程式碼
補充說明
這個方法確實很取巧,像lyh2668
所說的單純從length
判斷會有很多場景有問題。比如 有一個page5
介面,我需要能從page3
和page4
介面都能跳轉過去的話,那就需要為page5
配置兩個路由path
了,假設page
幾的path
層級就是幾的話,那麼就要為page5
配置層級4和層級5的兩個路由路徑了(當然直接就配置一個路由層級5的話也是可行的,只需要保證比跳轉到它的介面的層級都大就可以)。
另外可以像lyh2668
所說的把keepAlive
換成noKeepAlive
,這樣的話就不用在每個router
中去配置keepAlive
了,就方便了很多。關於層級也可以不通過/
來判斷,比如在path
末尾加數字等其它方式來實現。
另外lyh2668
所說的壓棧的方式,我也有搜到過,但是在有tab
介面的時候這種方式就不適合了,因為tab
介面切換的時候不需要這種效果,但也會被壓棧。但是用我的方法的話,就可以把tab
介面的路由都設定為同一個層級,就不會有問題了
這是是壓棧方式的程式碼,在沒有tab介面的時候,這種方式確實會更好用。
let routerList = []
router.beforeEach((to, from, next) => {
if (routerList.length && routerList.indexOf(to.name) === routerList.length - 1) {
// 後退
routerList.splice(routerList.length - 1, 1)
to.meta.isBack = true
} else {
// 前進
routerList.push(from.name || '/')
to.meta.isBack = false
}
next()
})
複製程式碼
歡迎有更好方法的朋友能夠指點分享。
已新增Demo
說明,見github。包括普通介面切換、tab
介面切換和不同層級介面的切換示例。