1、keep-alive的使用
在SPA應(yīng)用中,我們有時(shí)候需要來(lái)回的切換路由,而組件就會(huì)重復(fù)的創(chuàng)建和銷毀。
keep-alive是Vue內(nèi)置的一個(gè)組件,它可以使被包含的組件保留狀態(tài),可以避免重復(fù)渲染。
相對(duì)應(yīng)的router-view也是一個(gè)組件,如果外面想所有路徑匹配到的視圖組件都能被緩存起來(lái),可以將它用keep-alive包裹起來(lái)。
app.vue
<template>
<div id="app">
<router-link to="/home">首頁(yè)</router-link>
<router-link to="/about">關(guān)于</router-link>
<router-link :to="'/user/' + userId">用戶</router-link>
<router-link :to="{path:'/profile',query:{name:'why',age:18,height:180}}">檔案</router-link>
<keep-alive>
<router-view></router-view>
</keep-alive>
</div>
</template>
home.vue
<template>
<div>
<h2>我是home組件</h2>
<router-link to="/home/news">新聞</router-link>
<router-link to="/home/message">消息</router-link>
<router-view></router-view>
</div>
</template>
<script>
export default{
created() {
console.log('home created');
},
destroyed() {
console.log('home destroyed');
}
}
</script>
<style>
</style>
如上圖所示,我們?cè)?strong>app.vue中用keep-alive把這四個(gè)組件都緩存起來(lái),這里我們只在home.vue中檢驗(yàn)他的創(chuàng)建和銷毀,運(yùn)行、切換home created,只輸出了一次,home destroyed沒(méi)有輸出;則表示組件只被創(chuàng)建了一次,且被緩存起來(lái)并沒(méi)有被銷毀。
但如果說(shuō)向home.vue中也有兩個(gè)子組件展示的時(shí)候,切換路由,返回的時(shí)候還是要展示上次離開時(shí)的組件;則home.vue中script位置應(yīng)該改成如下:
<script>
export default{
data() {
return {
path: '/home/news'//初始顯示組件路由
}
},
created() {
console.log('home created');
},
destroyed() {
console.log('home destroyed');
},
activated() {
console.log('activated',this.path);
this.$router.push(this.path)
},
// deactivated() {
// this.path = this.$route.path
// console.log('deactivated',this.path);
// },
beforeRouteLeave(to,from,next) {
this.path = this.$route.path
console.log('beforeRouteLeave',this.path);
next()
}
}
</script>
activated()和activated()方法只有在keep-alive組件中才有效果,不然是無(wú)效的。
我們這里的原理是:
- 1、設(shè)置一個(gè)變量path來(lái)保存離開時(shí)的路由。
- 2、當(dāng)組件狀態(tài)變?yōu)榛钴S后跳轉(zhuǎn)為離開時(shí)路由。
至于為什么不在上面的deactivated()中通過(guò)this.path = this.$route.path獲取路由,那是因?yàn)樵摲椒▓?zhí)行的時(shí)機(jī)this.$route.path已經(jīng)不是我們所想要保存的路由,而是跳轉(zhuǎn)之后顯示出來(lái)組件的路由,所以我們這里通過(guò)beforeRouteLeave()方法來(lái)獲取離開組件時(shí)路由。
2、Uncaught (in promise) NavigationDuplicated: Avoided redundant navigation to current location: "/xxx/xxx"
這里我們還會(huì)碰到一個(gè)小問(wèn)題,當(dāng)我們從其他組件切換會(huì)home.vue組件時(shí)會(huì)執(zhí)行push方法,而當(dāng)組件變?yōu)榛钴S狀態(tài)時(shí)還會(huì)調(diào)用一次push方法,當(dāng)兩次push地址相同時(shí),則會(huì)報(bào)Uncaught (in promise) NavigationDuplicated: Avoided redundant navigation to current location: "/home/news".
解決方法:
- 1、在router配置文件(/router/index.js)下添加
const VueRouterPush = Router.prototype.push
Router.prototype.push = function push (to){
return VueRouterPush.call(this,to).catch(err => err)
}
- 2、使用 catch 方法捕獲異常
this.$router.push(route).catch(err => {
console.log('跳轉(zhuǎn)異常:',err)
})
- 3、在進(jìn)行路由跳轉(zhuǎn)時(shí)添加判斷,若一致則不跳轉(zhuǎn)
go(item) {
if (this.$route.path !== item.url) {
this.$router.push({ path: item.url })
}
}
3、keep-alive的exclude屬性
exclude:字符串或正則表達(dá)式,任何匹配的組件都不會(huì)被緩存
這里以profile.vue組件驗(yàn)證為例
<template>
<div>
<h2>我是profile組件</h2>
<p>{{$route.query.name}}</p>
<p>{{$route.query}}</p>
</div>
</template>
<script>
export default{
name:'profile',
created() {
console.log('profile created');
},
destroyed() {
console.log('profile destroyed');
},
}
</script>
<style>
</style>
注:這里要設(shè)置script中的name屬性,以便于keep-alive組件識(shí)別匹配組件。
而在keep-alive使用以下設(shè)置
<keep-alive exclude="profile">
<router-view></router-view>
</keep-alive>
這樣就做到了profile.vue組件的隨時(shí)創(chuàng)建和隨時(shí)銷毀