路由可向路由匹配的組件傳遞參數,不同情況
向組件傳遞不同的參數,從而實現組件的複用。
路由向組件傳遞參數
和路由匹配的組件可以在組件中使用 $route
獲取路由上的參數:
傳參方式
:
、params
和query
:
在路徑傳遞參數
{
path: "/argu/:id/book",
name: "argu",
component: () => import("@/views/ArguPage")
}
路徑
中的一部分是參數,必須
傳遞該參數:
<!--路徑跳轉-->
<router-link to="/argu/123/book">path跳轉</router-link>
<!--路由名跳轉-->
<router-link :to="{name:'argu',params:{id:'test'}}" tag="button">name+params跳轉</router-link>
<!--獲取參數-->
<h1>{{$route.params.id}}</h1><!--params的名字路徑中的的參數名一致-->
此時 path
+ parmas
傳遞參數,params
會被忽略。
params
+name
傳遞參數
路由:
{
path: "/argu",
name: "argu",
component: () => import("@/views/ArguPage")
}
跳轉方式是 name
+params
+(query),通過path
跳轉,params 會被忽略。
<router-link :to="{name:'argu', params:{name:'hangge'}}">
跳轉到 hello
</router-link>
// path + params ,params 會被忽略,因爲路徑中沒有定義參數
<router-link :to="{path:'/argu', params:{name:'hangge'}}">
跳轉到 hello
</router-link>
query 參數
query 參數參數,表現爲查詢字符串,和localtion.serach
一樣的。
不需要先在路徑中先定義,可通過path
、path
+query
或者 name
+ query
傳遞參數。
<router-link to="/argu?queryName=value">跳轉到 hello</router-link>
<router-link :to="{path:'/argu',query:{queryName:value}}">跳轉到 argu</router-link>
<router-link :to="{name:'argu',query:{queryName:value}}">跳轉到 argu</router-link>
<h1>{{ $route.query.queryName }}</h1>
函數傳遞 query
// 主要是 $router 不是 $route
go() {
this.$router.push({
name: 'argu',
query: {
queryName: "你好"
}
})
}
}
但是這樣使得 $route
和組件耦合在一起,不方便組件的複用,如果能將路由中的參數傳遞到 組件的props
就好了,恰恰是可以這樣設置的。
props 接收路由的 params
路由傳參數的三種方式:
- 布爾模式
{
path: '/user/:id',
component: User,
props: true //表明 將 id 作爲 proos 傳遞到匹配的組件 User 中。
}
User 中定義 props 接收 id:
export default {
props:{
id:{
type:String,
default:'jackzhou'//默認值
}
}
}
- 對象模式
將路由的 props
屬性設置一個對象,也可在組件中獲取到該值,這種方式往往用於傳遞靜態值,即 name 值不會變化。
路由對象:
{
name: 'home',
alias:'/home_page',
path: '/',
props:{name:'jack jack'},
component: Home
}
Home 組件:
props:{
name:{
type:String,
}
}
- 函數模式
以上兩種方式,params 參數的名字必須和組件中的props 屬性名字相同,如果想對 params 進行改造後傳遞到組件,就可將 props
設置成函數,在函數內獲取路由中的 params 或者 query,或者其他屬性值,對其進行處理後再傳遞給組件。
注意:這種方式函數必須返回一個對象。
路由:
{
name: 'about',
path: '/about/:years', //params 有一個參數 years
props:(route) {
const now = new Date()
return {
// 將 years 改造成 name
name: (now.getFullYear() + parseInt(route.params.years)) + '!'
}
},
component: () => import('@/views/AboutPage'),
}
組件中的 props:
props: {
name: {
type: String
}
}
命名視圖的路由,要爲每個命名視圖添加 props
:
{
path:'/name/:view',
name:'name_view',
components:{
default:()=>import('@/views/ChildPage'),
sister:()=>import('@/views/SisterPage'),
brother:()=>import('@/views/BrotherPage'),
},
props:{
default:true,
sister:false,
brother:(route)=>({view:route.params.view.toUpperCase()})
}
}
完整的例子
{% raw %}
<p class="codepen" data-height="573" data-theme-id="0" data-default-tab="js,result" data-user="JackZhouMine" data-slug-hash="JqBzWE" style="height: 573px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="route 的 params 傳遞組件">
<span>See the Pen
route 的 params 傳遞組件 by JackZhouMine (@JackZhouMine)
on CodePen.</span>
</p>
<script async src="https://static.codepen.io/ass...;></script>
{% endraw %}
HTML5 History 模式
路由配置裏有一個屬性 mode
,默認值是 hash
,以hash來模擬一個url,url改變時,頁面不會重新加載。
先使用普通模式,可將 mode
設置成 history
,這種模式會使用 history.pushSate
來完成url跳轉而頁面不會重新加載。這種模式需要服務器設置一下。
使用 history 模式,因爲web應用往往是單頁應用,當用戶訪問一個不存在的路徑時,需要提供一個後備頁面。
在路由配置的最後增加一個404路由:
{
path:'*',
component:NotFoundPage// 前面沒有匹配的路由,最後會匹配該路由。
}
meta 元信息
可在路由對象中配置 meta
屬性,meta 是一個對象。
比如,根據不同頁面顯示不同的 title。
{
name: "about",
path: "/about",
meta: {
title: "關於"
},
component: () => import("@/views/AboutPage")
}
在路由配置文件中,設置各個頁面的 title:
const router= new Router({
routes
})
router.beforeEach((to,from,next)=>{
//setTitle 函數用於設置頁面標題
to.meta&&setTitle(to.meta.title) //這是簡化if語句的簡寫
console.table(to)
console.table(from)
next()
})
export default router
導航守衛
全局守衛
- 全局前置守衛
const router = new Router({
{
path:"/",
name:"heom_page"
component:Home,
//路由獨享守衛
beforeEnter:(to,from,next)=>{
//處理邏輯
next()
}
}
})
//每次路由進入都會調用
router.beforeEach((to,from,next)=>{
//處理邏輯,比如登錄判斷,可跳轉到任意頁面
//不要忘記調用 next,不調用 next,頁面不會跳轉
})
- 後置鉤子
//路由跳轉之後做一些操作,比如去掉登錄樣式
router.afterEach((to,form)=>{
//邏輯處理
})
- 路由獨享守衛
只在匹配某個路由時執行。
- 組件內守衛
beforeRouteEnter
, 組件創建之前調用,組件不具備this
;beforeRouteUpdate
,路由更新,而組件被複用時調用,可使用this
;beforeRouteLeave
,離開路由時調用,可使用this
。
export default{
name:'Home',
data(){
return {}
},
/**
* 組件內路由守衛
* 1. 該函數在路由進入時執行
* 2. 此時 組件還未渲染,不可用 this,當可在 next 中用 vm
* 3. next 晚於 mounted 執行,next 之前的代碼,早於beforeCreate * 執行
* 4. 最後需要調用 next 使得路由跳轉
*/
beforeRouteEnter(to, from, next) {
console.log("①,home 組件內路由守衛,beforeRouteEnter");
// next 晚於 mounted 執行,next 之前的代碼,早於beforeCreate 執行
next((vm)=>{
console.log('vm')
console.log(vm)//有值
console.log('this')
console.log(this)// undefined
console.log('②,home 組件內路由守衛,beforeRouteEnter');
});
},
/**
* 組件內路由守衛
* 1. 該函數在路由離開時執行,最先調用,然後在調用全局守衛,再調用 * beforeDestroy
* 2. 此時,該路由守衛所在組件已渲染,可用 this
* 3. 最後需要調用 next 使得路由跳轉
*/
beforeRouteLeave(to, from, next) {
console.log("①,home 組件內路由守衛,beforeRouteLeave");
let leave = confirm("你確定要離開 home 頁嗎?");
if (leave) {
// console.log(to.name, from.name);
// console.log(this);
next(() => {
console.log('②,home 組件內路由守衛,beforeRouteLeave');
}); //給 next 傳遞 false ,路由不會跳轉
} else {
next(false);
}
},
/*
* 當路由發生變化,而組件被複用時調用
* 1. 此時該複用組件已被渲染,可用 this
* 2. 需要調用 next,組件才能渲染
*/
beforeRouteUpdate(to, from, next) {
console.log('①,argu,組件內路由守衛,beforeRouteUpdate');
next(() => {
console.log('next,argu,組件內路由守衛,beforeRouteUpdate');
});
},
beforeCreate() {
console.log('beforeCreate')
},
created() {
console.log('created')
},
beforeMount() {
console.log('beforeMount')
},
mounted() {
console.log('mounted')
},
beforeUpdate() {
console.log('beforeUpdate')
},
updated() {
console.log('updated')
},
beforeDestroy() {
console.log('beforeDestroy')
},
destroyed() {
console.log('destroyed')
}
}
路由全過程:
- 導航被觸發
- 離開頁面(失活的組件)裏調用離開守衛 beforeRouteLeave
- 調用
全局前置守衛
beforeEach - 在重用的組件裏調用 beforeRouteUpdate (非重用組件,沒有這個步驟)
- 調用路由獨享守衛 beforeEnter
- 解析異步路由組件
- 在進入頁面(激活組件)調用 beforeRouteEnter
- 調用
全局解析守衛
beforeResolve (導航被確認之前,組件內守衛和異步路由組件被解析之後,調用 beforeResolve) - 導航被確認(什麼時候被確認,全部鉤子執行完了,是被確認的)
- 調用
全局後置守衛
afterEach - 觸發 DOM 更新
- 在 vue 實例中(此時頁面解析完畢了嗎?是的)調用 beforeRouterEnter 守衛裏傳給 next 的回調。
next
在mounted
之後被調用。
過渡效果
可以給路由匹配的組件設置過渡效果,讓頁面平滑地顯示,提升用戶體驗。
需要用到 transition
標籤,如果有多個視圖需要過渡,則用 transition-group
。
<transition-group name='router-view'>
<!-- 視圖渲染組件,該組件內不需要房子任何內容,可寫成只閉合標籤-->
<router-view key='default'/>
<!-- 有多個路由視圖需要匹配,則用命名視圖 -->
<router-view key='sister' name="sister"></router-view>
<router-view key='brother' name="brother"></router-view>
</transition-group>
css 過渡效果:
.router-view-enter{
opacity: 0;
}
.router-view-enter-active{
transition: opacity 1s ease;
}
.router-view-enter-to{
opacity: 1;
}
.router-view-leave{
opacity: 1;
}
.router-view-leave-active{
transition: opacity 1s ease;
}
.router-view-leave-to{
opacity: 0;
}
這些設置,每個頁面的效果都是一樣的,要爲不同的頁面設置不同的效果,可用路由傳遞相應的參數來,讓動態綁定到 transition 的 name 屬性上。
或者監聽路由變化:
watch: {
'$route'(to){
console.log(to);
to.params&&to.params.view&&(this.effect = to.params.view)
},
}