個人自學前端33-Vue10-路由守衛
阿新 • • 發佈:2021-10-07
目錄
一. 路由守衛
路由守衛一定會用到的api
路由守衛也叫路由鉤子,路由生命週期 => 路由守衛其實都是在路由跳轉的特定階段觸發的函式。
路由跳轉流程。
- 路由觸發,準備跳轉
- 觸發Home元件的一個鉤子函式,beforeRouteLeave (路由離開前)
- 呼叫全域性的 beforeEach(所有路由跳轉都會觸發的一個鉤子) 鉤子
- 在重用的元件(動態路由元件)裡呼叫 beforeRouteUpdate.(當前路由元件更新時)
- 在路由配置裡呼叫 beforeEnter(路由選項獨享守衛)
- 解析非同步路由(路由懶載入)元件。
- 在News元件裡呼叫 beforeRouteEnter (當前路由準備進入時)。
- 呼叫全域性的 beforeResolve (完成跳轉前)。
- 導航被確認。(完成路由跳轉)
- 呼叫全域性的 afterEach 鉤子。
- 觸發 DOM 更新(更新路由元件檢視)
- 呼叫 beforeRouteEnter 守衛中傳給 next 的回撥函式,建立好的元件例項會作為回撥函式的引數傳入。
守衛分類:
- 全域性守衛
beforeEach (很常用)
beforeResolve
afterEach - 路由獨享守衛
beforeEnter - 元件獨享守衛
beforeRouteEnter (常用)
beforeRouteUdpate (常用)
beforeRouteLeave (常用)
1. 路由守衛的引數
- to 目標路由的$route物件
- from 起始路由的$route物件
- next 回撥函式,用於攔截路由或者路由傳參
next的引數:- 沒引數 => 正常跳轉
- false => 不讓跳轉
- 字串路徑 => 重定向
- 物件 => 重定向時路由傳參.
- 函式 => 跳轉的最後節點觸發,引數是當前的元件例項.
const Home = { template: ` <div> <h3>首頁</h3> </div> `, // Home路由跳轉到其他路由前觸發的鉤子守衛. beforeRouteLeave(to, from, next) { // console.log('準備離開Home'); // 通過to物件,可以知道目標路由是哪個 console.log('to', to.path); // 通過from物件,可以知道起始路由是哪個. console.log('from', from.path); // next是一個回撥函式 console.log('next', next); // 手動呼叫next才能正常跳轉路由(一定不要忘記) next(); // 引數寫false就是跳轉失敗 // next(false); } } const News = { template: ` <div> <h3>新聞</h3> </div> `, data() { return { msg: 'News元件' } }, // 元件進入前的守衛.(別的路由進入News路由時觸發) // beforeRouteEnter鉤子內部能使用this. // 這裡的this不指向當前的News元件.而是window // beforeRouteEnter觸發時,元件還沒有建立 beforeRouteEnter(to, from, next) { // undefined console.log('msg',this.msg); // next的引數可以是一個回撥函式,在整個路由跳轉的最後階段觸發 // 這個回撥函式的引數就是當前的News元件例項. // next((vm) => { // console.log('msg', vm.msg) // }); // 進入News前,重定向到sport。 // next('/sport'); // 進入News前,重定向到sport,並且傳參msg給sport元件 next({ path: '/sport', query: { msg: 10000 } }); } } </script>
2.元件獨享守衛
beforeRouteLeave => 守衛(保安),可以讓路由跳轉被攔截 => 路由跳轉到其他路由前觸發的鉤子守衛.
beforeRouteEnter => 元件進入前的守衛.
beforeRouteLeave和beforeRouteEnter只能在路由元件中觸發.
在路由元件(routes中配置的元件)的子元件中是不觸發的.
動態路由間的切換時不會觸發beforeRouteLeave和beforeRouteEnter.
動態路由切換,可以通過beforeRouteUpdate來監測.
同樣的.beforeRouteUpdate在路由元件的子元件中也不觸發.
const box = {
template: `
<h3>box子元件</h3>
`,
// 這裡的leave的元件是不觸發的
beforeRouteUpdate(to, from, next) {
console.log('box的Update')
next();
}
}
const Home = {
template: `
<div>
<h3>首頁--{{$route.path}}</h3>
<box />
</div>
`,
components: { box },
// 動態路由中不觸發beforeRouteLeave
beforeRouteLeave(to, from, next) {
console.log('Home的leave')
next();
},
// 動態路由切換時觸發.
beforeRouteUpdate(to, from, next) {
console.log(from.params.path + '到' + to.params.path);
next();
}
}
從非動態路由跳轉到動態路由,會觸發動態路由內的Enter.
從動態路由跳轉到非動態路由,會觸發動態路由內的Leave.
3. 全域性守衛
全域性守衛,所有的路由跳轉都會觸發這個鉤子.
beforeEach相對於是全域性的beforeRouteEnter(沒有全域性的Leave守衛)
router.beforeEach((to, from, next) => {
console.log('進入' + to.path + '元件');
next();
});
例子:簡易登入的守衛邏輯
<script>
// 一個App應用
// 1:有寫頁面需要登入,有些頁面不需要登入.
// 2:跳轉到需要登入的頁面時,先檢測你是不是已經登入了,如果沒有登入直接跳轉到登入頁.,如果登入了,直接跳轉.
// 預設沒有登入.
let isLogin = false;
const Login = {
template: `
<div>
<input type='text' />
<button @click='toPage'>登入</button>
</div>
`,
props: ['name'],
methods: {
toPage() {
// 切換登入狀態
isLogin = true;
// 跳轉到指定路由.
this.$router.push({ name: this.name })
}
}
}
const Home = {
template: `
<div>
<slot />
<h3>首頁</h3>
</div>
`,
}
const News = {
template: `
<div>
<slot />
<h3>新聞</h3>
</div>
`,
}
const Sport = {
template: `
<div>
<slot />
<h3>體育</h3>
</div>
`,
}
// 例項化路由
const router = new VueRouter({
// 路由元件和路由路徑的對應關係 => 路由選項
routes: [
{
path: '/home',
component: Home,
name: 'home',
meta: {
// 不需要登入
authLogin: false
}
}, {
path: '/news',
component: News,
name: 'news',
meta: {
authLogin: true
}
}, {
path: '/sport',
component: Sport,
name: 'sport',
meta: {
authLogin: true
}
}, {
path: '/login',
component: Login,
name: 'login',
meta: {
authLogin: false
},
props: true
},{
path: '/',
redirect: '/home'
}
]
});
// 全域性守衛處理 登入邏輯
router.beforeEach((to, from, next) => {
if (to.meta.authLogin) {
if (!isLogin) {
// 重定向,並且傳遞目標路由的name
next({ name: 'login', params: { name: to.name }})
} else {
next()
}
} else {
next()
}
});
const App = {
template: `
<div>
<router-view>
<router-link to='/home'>首頁</router-link>
<router-link to='/news'>新聞</router-link>
<router-link to='/sport'>體育</router-link>
</router-view>
</div>
`
};
new Vue({
render: h => h(App),
// 掛載路由
router
}).$mount('#app');
</script>
4.路由獨享守衛
const router = new VueRouter({
routes: [
{
path: '/home',
component: Home
}, {
path: '/news',
component: News,
components: { Home, box },
// 對於選項的components有意義
// News選項獨享的守衛,寫在這裡和寫在元件中的效果一致.
// 這裡沒辦法通過next的回撥獲取元件例項.
beforeEnter(to, from, next) {
console.log('Enter');
next();
}
}, {
path: '/sport',
component: Sport
}, {
path: '/',
redirect: '/home'
}
]
})
5.如何在路由跳轉時實現一些額外的邏輯?
如何監聽路由的跳轉?
- 不快取元件的情況
- created和mounted中監聽.
- watch監聽$route變化(任意元件中都可以使用)
- 路由守衛監聽.(只能在路由元件中使用)
- 快取的元件
- watch監聽$route變化
- ativated和deactivated.(路由元件和路由元件的子元件都可以觸發)
- 路由守衛監聽.(只能在路由元件中使用)
- 動態路由
- watch監聽$route變化
- beforeRouteUpdate守衛監聽
watch監聽例子:
<script>
const Home = {
template: `
<div>
<h3>首頁</h3>
</div>
`,
created() {
console.log('Home元件切換11');
},
watch: {
// 每次路由發生跳轉,路徑都會改變,路徑改變$route內的屬性就會變,從而觸發watch
'$route': {
immediate: true,
handler() {
console.log('Home元件切換22');
}
}
},
beforeRouteEnter(to, from, next) {
console.log('Home元件切換33');
next();
}
}
const News = {
template: `
<div>
<h3>新聞</h3>
</div>
`,
data() {
return { msg: 'News元件' }
}
}
const Sport = {
template: `
<div>
<h3>體育</h3>
</div>
`
}
const router = new VueRouter({
routes: [
{
path: '/home',
component: Home
}, {
path: '/news',
component: News
}, {
path: '/sport',
component: Sport
}, {
path: '/',
redirect: '/home'
}
]
})
const App = {
template: `
<div>
<router-link to='/home'>首頁</router-link>
<router-link to='/news'>新聞</router-link>
<router-link to='/sport'>體育</router-link>
<router-view />
</div>
`,
watch: {
$route: {
immediate: true,
handler() {
console.log('路由切換了')
}
}
}
};
new Vue({
render: h => h(App),
// 掛載路由
router
}).$mount('#app');
</script>