vue 路由進階

路由可向路由匹配的組件傳遞參數,不同情況向組件傳遞不同的參數,從而實現組件的複用。

路由向組件傳遞參數

和路由匹配的組件可以在組件中使用 $route 獲取路由上的參數:

傳參方式

:paramsquery

:在路徑傳遞參數

{
    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一樣的。

不需要先在路徑中先定義,可通過pathpath+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

路由傳參數的三種方式:

  1. 布爾模式
{
    path: '/user/:id', 
    component: User, 
    props: true //表明 將 id 作爲 proos 傳遞到匹配的組件 User 中。
}

User 中定義 props 接收 id:

export default {
    props:{
        id:{
            type:String,
            default:'jackzhou'//默認值
        }
    }
}
  1. 對象模式

將路由的 props 屬性設置一個對象,也可在組件中獲取到該值,這種方式往往用於傳遞靜態值,即 name 值不會變化。

路由對象:

{
    name: 'home',
    alias:'/home_page',
    path: '/',
    props:{name:'jack jack'},
    component: Home
}

Home 組件:

props:{
    name:{
        type:String,
    }
}
  1. 函數模式

以上兩種方式,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

導航守衛

全局守衛

  1. 全局前置守衛
const router = new Router({
    {
        path:"/",
        name:"heom_page"
        component:Home,
        //路由獨享守衛
        beforeEnter:(to,from,next)=>{
            //處理邏輯
            next()
        }
    }
})
//每次路由進入都會調用
router.beforeEach((to,from,next)=>{
    //處理邏輯,比如登錄判斷,可跳轉到任意頁面
    //不要忘記調用 next,不調用 next,頁面不會跳轉
})
  1. 後置鉤子
//路由跳轉之後做一些操作,比如去掉登錄樣式
router.afterEach((to,form)=>{
    //邏輯處理
})
  1. 路由獨享守衛

只在匹配某個路由時執行。

  1. 組件內守衛

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')
    }
}

路由全過程:

  1. 導航被觸發
  2. 離開頁面(失活的組件)裏調用離開守衛 beforeRouteLeave
  3. 調用全局前置守衛 beforeEach
  4. 在重用的組件裏調用 beforeRouteUpdate (非重用組件,沒有這個步驟)
  5. 調用路由獨享守衛 beforeEnter
  6. 解析異步路由組件
  7. 在進入頁面(激活組件)調用 beforeRouteEnter
  8. 調用全局解析守衛 beforeResolve (導航被確認之前,組件內守衛和異步路由組件被解析之後,調用 beforeResolve)
  9. 導航被確認(什麼時候被確認,全部鉤子執行完了,是被確認的)
  10. 調用全局後置守衛 afterEach
  11. 觸發 DOM 更新
  12. 在 vue 實例中(此時頁面解析完畢了嗎?是的)調用 beforeRouterEnter 守衛裏傳給 next 的回調。nextmounted之後被調用。

過渡效果

可以給路由匹配的組件設置過渡效果,讓頁面平滑地顯示,提升用戶體驗。
需要用到 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)
    },
}

參考

Vue.js - 路由 vue-router 的使用詳解2(參數傳遞)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章