vue系列教程-11vuerouter路由

本內(nèi)容為系列內(nèi)容,全部內(nèi)容請看我的vue教程分類

什么是路由

大家還記得我最開始提到的spa單頁面嗎,通過不同的路徑顯示不同的組件,這個就是通過router實(shí)現(xiàn)的

那么首先我們還需要引入一個 router文件

<script src="https://cdn.bootcss.com/vue-router/3.1.3/vue-router.js"></script>

這里的話我們還是以上面的bilibili消息中心為示例,使用到剛剛的代碼

還是先定義組件模板

<template id="writeback">
    <div>
        <div>回復(fù)我的</div>
        <div>這是回復(fù)我的界面</div>
    </div>
</template>
<template id="aite">
    <div>
        <div>@我的</div>
        <div>這是@我的界面</div>
    </div>
</template>
<template id="zan">
    <div>
        <div>收到的贊</div>
        <div>這是收到贊的界面</div>
    </div>
</template>

然后定義組件

const writeback = {
    template: '#writeback'
}
const aite = {
    template: '#aite'
}
const zan = {
    template: '#zan'
}

基礎(chǔ)使用

在組件那一節(jié)我們是通過動態(tài)組件來實(shí)現(xiàn)界面切換的,這里我們就使用路由來實(shí)現(xiàn)頁面切換

這里我們實(shí)例化vue的時候,屬性里面的 router傳入一個 VueRouter 的實(shí)例,這個數(shù)組routes就是詳細(xì)的路徑和對應(yīng)的組件信息,比如我們?yōu)g覽器訪問 www.lookroot.cn/writeback的時候,頁面就展示上面定義好的 writeback組件

let vm = new Vue({
    el: '#app',
    data() {
    },
    router: new VueRouter({
        routes: [
            {
                path: '/writeback',
                component: writeback
            },
            {
                path: '/aite',
                component: aite
            },
            {
                path: '/zan',
                component: zan
            },
        ],
    })
})

那么原本的導(dǎo)航也要進(jìn)行修改 這個 router-link就會在頁面中渲染成a標(biāo)簽,作為導(dǎo)航

<div class="bili-leftnav">
    <ul>
        <li>
            <router-link to="/writeback">回復(fù)我的</router-link>
        </li>
        <li>
            <router-link to="/aite">@我的</router-link>
        </li>
        <li>
            <router-link to="/zan">收到贊的</router-link>
        </li>
    </ul>
</div>

那么我們原本的選中效果是沒有了的因?yàn)闆]有綁定點(diǎn)擊事件,但是路由會給默認(rèn)激活的導(dǎo)航加上一個class名為router-link-active ,我們簡單編寫一下

 /* 當(dāng)前顯示路由的顏色 */
 .bili-content .bili-leftnav li .router-link-active {
     color: #2fbbea;
 }

然后和動態(tài)組件一樣要有個展示的容器吧,這里我們也給它加上過渡動畫,這個router-view就是路由界面的展示容器和動態(tài)組件的component是一樣的

<div class="bili-rightcontent">
    <transition enter-active-class="animated fadeInDown" leave-active-class="animated fadeInUp"
        mode="out-in" :duration="200">
        <router-view></router-view>
    </transition>
</div>

好的這就完成了改造了看看效果吧完全是可以的,注意看路徑的變化

vue教程-lookroot

路由重定向

如果我們打開這個界面的時候,路徑后面沒有跟著具體的路徑,界面就不會顯示任何的組件,這肯定是不友好的

必須設(shè)置一個默認(rèn)界面,我們咋路由配置文件里面增加一個路由信息

{
    path: '/',
    redirect: '/writeback',
},

這里的意思就是,默認(rèn)為初始界面的時候,就重定向到 writeback這個路徑,這樣writeback就成了默認(rèn)界面了

命名視圖和命名路由

命名視圖

如果我們頁面中同時有兩個<router-view></router-view>的時候,點(diǎn)開頁面要展示兩個組件,那么你怎么知道哪個組件應(yīng)該展示到哪個 view里面呢?這就是命名視圖

我們在添加一個 view,并且namecommon

<div class="bili-rightcontent">
    <transition enter-active-class="animated fadeInDown" leave-active-class="animated fadeInUp"
        mode="out-in" :duration="200">
        <router-view></router-view>
    </transition>
    <router-view  name="common"></router-view>
</div>

定義一個組件模板

<template id="vuefooter">
    <div>
        <h2>footer</h2>
    </div>
</template>

定義這個組件

const vuefooter = {
    template: '#vuefooter'
}

然后修改一下 writeback的路由配置,component就換成components了,并且默認(rèn)的容器展示writeback組件,命名為common的容器展示 剛剛定義的這個vuefooter組件

{
    path: '/writeback',//點(diǎn)擊的路徑
    // 命名視圖
    components: {
        default: writeback,
        common: vuefooter
    },
},

看看效果,是可以的,這就是命名視圖

vue教程-lookroot

命名路由

我們給路由也起名字,這樣方便使用,這里還是以 writeback為例

{
    path: '/writeback',//點(diǎn)擊的路徑
    // 命名視圖
    components: {
        default: writeback,
        common: vuefooter
    },
    // 命名路由
    name: 'writeback',
},

修改它的導(dǎo)航鏈接,這樣就完成了

<router-link :to="{name:'writeback'}">回復(fù)我的</router-link>

嵌套路由和路由傳參

這個嵌套大家就知道了,肯定是路由中有路由,就像組件中有組件一樣,又是套娃行為

來看下這個界面,1部分是導(dǎo)航,2部分是路由展示的組件同時相對于3部分又是一個導(dǎo)航,3部分是路由展示的組件,這就是一個很明顯的路由嵌套,我們就來實(shí)現(xiàn)一下

vue教程-lookroot

首先我們要添加這個我的消息這個導(dǎo)航鏈接

 <div class="bili-leftnav">
     <ul>
         <li>
             <router-link :to="{name:'writeback'}">回復(fù)我的</router-link>
         </li>
         <li>
             <router-link to="/aite">@我的</router-link>
         </li>
         <li>
             <router-link to="/zan">收到贊的</router-link>
         </li>
         <li>
             <router-link to="/mymsg">我的消息</router-link>
         </li>
     </ul>
 </div>

然后定義第二部分和第三部分的組件

這個第二部分的組件模板,它里面首先是一個導(dǎo)航,這個導(dǎo)航我循環(huán)渲染出來的,模擬了十個用戶聊天導(dǎo)航,并且是使用了 :to也就是綁定動態(tài)的路徑,路徑后面跟上了 index也就是把當(dāng)前是第幾個用戶傳遞給第三部分這就是路由傳參params方式

路由傳參params方式

<template id="mymsg">
    <div>
        <div>消息</div>
        <div>
            <ul>
                <ol v-for="index in 10" >
                    <router-link :to="'/mymsg/msgcontent/'+index">用戶{{index}}</router-link>
                </ol>
            </ul>
            <router-view></router-view>
        </div>
    </div>
</template>

定義第三部分組件模板

<template id="msgcontent">
    <div>
        這是和用戶{{id}}具體的消息界面
    </div>
</template>

定義這兩個組件,為什么要使用 props來接受傳值那?下面解釋

//第二部分組件
const mymsg = {
    template: '#mymsg',
}
//第三部分組件
const msgcontent = {
    template: '#msgcontent',
    props: ['index'],
}

嵌套路由

然后定義這個嵌套路由,這個 mymsg就是第二部分的路由配置,然后給它配置一個children這里面就是嵌套的路由配置了,首先path后面的 :id就是匹配我們上面定義的router-link傳參的index,這個props: true就是將我們傳遞的index值,自動注冊為第三部分組件的 props

// 嵌套路由
{
    path: '/mymsg',
    component: mymsg,
    children: [{
        path: 'msgcontent/:index',
        component: msgcontent,
        props: true
    }]
}

看下效果,這就完成了

vue教程-lookroot

路由傳參query方式

我們回到前面的第一部分的導(dǎo)航,修改一下這個我得消息的導(dǎo)航,使用?連接傳遞值

<router-link to="/mymsg?username=lookroot">我的消息</router-link>

如果我們不適用上面的props來接受傳值該怎么做呢?

修改一下組件定義,created周期時使用this.$route.query來接受query方式的傳值,賦值給username

const mymsg = {
    template: '#mymsg',
    data() {
        return {
            username: ''
        }
    },
    created() {
        // query傳值
        this.username = this.$route.query.username
    },
}

然后在組件模板中渲染這個數(shù)據(jù)

<template id="msgcontent">
    <div>
        這是和用戶{{id}}具體的消息界面
    </div>
</template>

看下效果是可以的

vue教程-lookroot

@[toc]

路由模式

路由有兩種模式historyhash模式,默認(rèn)也就是我們前面使用的模式是hash模式

這種模式就是在后面跟著一長串,不是很好看,如果追求美觀就可以使用history模式

來實(shí)例一下

定義兩個組件模板

<template id="page1">
    <div>
        page1
    </div>
</template>
<template id="page2">
    <div>
        page2
    </div>
</template>

定義這兩個組件

const page1 = {
    template: '#page1',
}
const page2 = {
    template: '#page2',
}

實(shí)例化一個router,指定modehistory模式

 const router = new VueRouter({
     mode: 'history',
     routes: [
         {
             path: '/',
             redirect: '/page1',
         },
         {
             path: '/page1',
             component: page1,
             name: 'page1',
         },
         {
             path: '/page2',
             component: page2,
             name: 'page2',
         },
     ],
 });

在頁面中定義導(dǎo)航,這里我們介紹另外一種路由跳轉(zhuǎn)的方式編程式的導(dǎo)航

<div id="app">
    <!-- <router-link to="/page1">page1</router-link> -->
    <button @click="gotoPage('/page1')">page1</button>
    <button @click="gotoPage('/page2')">page2</button>
    <router-view></router-view>
</div>

那么這里都綁定上一個點(diǎn)擊事件,然后傳遞一個地址字符串

編程式的導(dǎo)航

在當(dāng)前組件(父組件)中編寫一下這個點(diǎn)擊事件,使用this.$router.push進(jìn)行路由跳轉(zhuǎn)

methods: {
    gotoPage(path) {
        // 編程式的導(dǎo)航 
        this.$router.push(path)
    }
},

運(yùn)行一下查看效果,看下導(dǎo)航欄地址是不是就美觀多了啊

vue教程-lookroot

但是這個模式有問題的,比如我們直接在瀏覽器中打開這個鏈接是會報錯的

vue教程-lookroot

解決這個問題的方法需要后端處理官網(wǎng)文檔

全局路由守衛(wèi)

顧明思議,守衛(wèi)嘛,就是攔截放行的效果

這里我們舉一個登錄的示例,但只是簡單的舉例哦,真實(shí)開發(fā)并不是這樣做的

首先我們在vue的原型指向上掛載一個屬性,用來記錄用戶是否登錄

Vue.prototype.isLogin = false

然后編寫,第三個組件 login,并添加一個login點(diǎn)擊事件

<template id="login">
    <div>
        <button @click="login">login</button>
    </div>
</template>

然后定義這個組件,并編寫點(diǎn)擊事件,點(diǎn)擊就修改isLogin的值為 true,并使用this.$router.back返回上一個頁面

const login = {
    template: '#login',
    methods: {
        login() {
            Vue.prototype.isLogin = true;
            //返回的意思
            this.$router.back();
        }
    },
}

然后配置路由信息

{
    path: '/login',
    component: login,
    name: 'login'
},

好的定義全局守衛(wèi),記住要在定義router之后 to, from, next也不用解釋吧,語義化的,前置守衛(wèi)顧名思義也就是執(zhí)行之前會調(diào)用的,所以我們在這里進(jìn)行判斷用戶是否登錄,如果未登錄,我們就挑戰(zhàn)到 命名路由為login這個路由地址

 // 全局的 前置守衛(wèi)
 router.beforeEach((to, from, next) => {
         if (!Vue.prototype.isLogin) {
             next({
                 name: 'login'
             });
         } else {
             next();
         }
 })

效果就是我們點(diǎn)擊切換路由的時候,如果沒有登錄,就跳轉(zhuǎn)到登錄頁面,但是這里大家仔細(xì)想這樣一個問題,我的login路由同樣也會執(zhí)行守衛(wèi),同樣我也沒有登錄,然后他就會再次跳轉(zhuǎn),這樣就成了死循環(huán),怎么解決這個問題呢?

路由元信息

我們簡單修改一下路由配置,我們在需要判斷登錄的路由中加上meta: { isLogin: true },表明當(dāng)前路由是需要登錄的

routes: [
    {
        path: '/',
        redirect: '/page1',
        meta: { isLogin: true }
    },
    {
        path: '/page1',
        component: page1,
        name: 'page1',
        meta: { isLogin: true }
    },
    {
        path: '/page2',
        component: page2,
        name: 'page2',
        meta: { isLogin: true }
    },
    {
        path: '/login',
        component: login,
        name: 'login'
    },
],

然后我們怎么在路由守衛(wèi)中讀取這個字段那?

我們修改一下這個守衛(wèi),matched是路由記錄,那么我們就在要到達(dá)的路由中進(jìn)行查找字段to.matched.some(item => item.meta.isLogin)如果有這個字段的才進(jìn)行判斷

 router.beforeEach((to, from, next) => {
     // matched 路由記錄
     if (to.matched.some(item => item.meta.isLogin)) {
         if (!Vue.prototype.isLogin) {
             next({
                 name: 'login'
             });
         } else {
             next();
         }
     } else {
         // 執(zhí)行下一個鉤子
         next();
     }
 })

然后我們在else里面執(zhí)行 next();就是執(zhí)行下一個鉤子,也就是放行的意思

測試一下看看效果,我們先把mode改為hash方便測試,可以看到要先點(diǎn)擊login才能進(jìn)行訪問

vue教程-lookroot

組件內(nèi)的路由守衛(wèi)

大家記得有些網(wǎng)頁你點(diǎn)擊后退或者其他,會彈出提示 是否確定離開嗎?

我們來實(shí)踐一下,修改一下 page1的組件定義,在beforeRouteLeave的鉤子里面進(jìn)行判斷

const page1 = {
    template: '#page1',
    beforeRouteLeave(to, from, next) {
        const result = window.confirm('確定離開頁面嗎?將不會保存')
        if (result) {
            next()
        } else {
            next(false)
        }
    }
}
vue教程-lookroot

那么還有其他更多的路由參數(shù),這里就不一一講解了

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容