Javascript - Vue - 路由

vue router.js

下載:vue-router.jscss

該文件依賴於vue.jshtml

<script src="Scripts/vue-2.4.0.js"></script>   
<script src="/Scripts/vue-router.js"></script>
路由的做用

使用路由後,當前頁面的url地址就會多出一個#號,這個#號與html頁面的錨點相似,在route.js中它表示根據路由對象裏的路由配置在頁面中切換不一樣的路由組件以便展現在客戶端顯示。路由發起的請求會交給router對象進行處理後返回請求的資源而不是直接向服務端發起資源請求,使用路由的好處在於發起一個路由請求後瀏覽器地址欄的刷新按鈕並不會動,而常規的超連接請求會使頁面刷新。雖然二者都是向服務端發起請求,但router的路由機制能夠將客戶端請求所須要的vue組件靜態加載(不刷新地址欄)到當前頁面上顯示。vue

建立路由對象
<template id="loginTem">
    <div>登陸區域</div>
</template>

<template id="registerTem">
    <div>註冊區域</div>
</template>

<script>
    //客戶端路由老是與組件有關,因此首先建立組件
    var loginCom={
        template:"#loginTem"
    }

    var registerCom={
        template:"#registerTem"
    }

    var router = new VueRouter({
        //路由對象的routes屬性是一個集合,用於設定路由模板
        routes: [            
            { path: "/login", component: loginCom }, //路由模板,用於匹配客戶端路由請求,component在此處是外部的組件被註冊在路由中,稱爲路由組件
            { path: "/register", component: registerCom } //不一樣的路由模板對不一樣的路由請求進行匹配
        ]
    });
</script>
路由的運做過程

當在vue對象所監視的html中的超連接、按鈕等元素的點擊事件上發起一個客戶端路由請求後,這個請求會經過vue轉發到路由對象上(路由對象會在vue中註冊),路由對象根據routes集合裏的路由模板對路由地址請求進行路由匹配,匹配成功後就將註冊在路由模板裏的組件發送到客戶端顯示在html文檔上。vue-router

路由標籤

組件切換可使用component標籤,經過指定它的is屬性來切動態換組件,而路由組件的切換則是經過vue-router提供兩個html標籤來實現瀏覽器

router-view佈局

這個標籤是路由組件的容器,路由匹配的過程是:一旦瀏覽器發起路由請求,那麼vue對象就會截獲這個請求,再將請求轉交給路由模板進行匹配,匹配成功後會將對應的路由組件插入到router-view容器裏。因此,若是僅僅是發起了路由請求,但沒有設置router-view,那麼路由組件是不會顯示出來的。學習

<div id="box">
    <a href="#/login">login</a>
    <a href="#/register">register</a>
    <router-view></router-view> //組件已經被註冊爲路由組件,此處再也不以組件標籤名而是使用路由標籤來插入html文檔,vue的整個路由機制就是圍繞這個標籤作文章,針對不一樣的路由匹配展現不一樣的路由組件到這個router-view裏面去。
</div>

<template id="loginTem">
    <div>登陸區域</div>
</template>

<template id="registerTem">
    <div>註冊區域</div>
</template>

<script>
    //客戶端路由老是與組件有關,因此首先建立組件
    var loginCom={
        template:"#loginTem"
    }

    var registerCom={
        template:"#registerTem"
    }

    var router = new VueRouter({
        //路由對象的routes屬性是一個集合,用於設定路由模板
        routes: [            
            { path: "/login", component: loginCom }, //路由模板,用於匹配客戶端路由請求
            { path: "/register", component: registerCom } //不一樣的路由模板對不一樣的路由請求進行匹配
        ]
    });

    var vm = new Vue({
        el: "#box",
        router: router //將路由對象註冊到vue對象的router屬性中,使vue對象能夠監聽到它內部所包含的html元素的url請求的路由變化,而後調用路由對象對路由請求進行匹配
    });
</script>

router-link動畫

能夠替代a標籤,屬性to指向目標路由地址。其做用是發起路由請求,有三種方式能夠發起路由請求,1.點擊router-link或a標籤,2.直接在瀏覽器地址欄輸入路由地址,3.經過手動寫js程序發起路由請求。
<div id="box">
    <router-link to="/login" >登陸</router-link> //能夠添加tag屬性,如tag="div",這樣會把router-link渲染成div,且依然能夠點擊
    <router-link to="/register">註冊</router-link>   
    <router-view></router-view>
</div>

控制<router-link>的cssthis

var router = new VueRouter({
    routes: [
      ……
    ],
    linkActiveClass: "link-active"
});
.link-active {
    background#ffd800;
    color#fff;
} 
手動定向路由 redirect
routes: [
    {path:"/",redirect:"/login"}, //當首次顯示主頁時直接定向到登陸區域,或直接{path:"/",component:"loginCom"}使請求主頁時直接顯示登陸區域
    { path: "/login", component: loginCom }, 
    { path: "/register", component: registerCom }
]
路由命名 name
{path:"/index/productList",component:productList,name:"productList"}
手動發起路由請求 $router.push()

使用$router.push()方法,注意不是$route而是$router,給路由命名後,能夠經過點擊事件手動發起路由請求並傳遞url路由查詢字符串url

<div @click="redirect" > 商品購買</div >
methods{
    redirect: function() {
        this.$router.push({ name: "productList",params:productID });
       //或
        this.$router.push("/index/productList"+productID);
       //或
        this.$router.push({path:"/index/productList"+productID});
    }
}
路由匹配中的查詢字符

非嚴格匹配 $route.query

路由地址的後面跟上查詢字符串可以被識別有效路由。好比請求的路由爲#/login,路由模板也能夠匹配#/login?id=100&name=sam。能夠在組件對象的內部經過組件建立完成以後觸發的事件、使用$route.query獲取查詢字符串的值

<router-link to="/login?id=100&name=sam">登陸</router-link>
//當前組件被初始化時打印路由地址中的查詢字符
var login={
    template: "#loginTem",
    created: function () {
        console.log(this.$route.query.id);
    }
}

嚴格匹配 $route.params

在路由模板裏能夠定義查詢字符的匹配規則,若是在路由模板裏定義了查詢字符的匹配的規則,那麼就必須包括查詢字符在內的路由地址得徹底符合路由模板的規則,不然不會被匹配。好比在路由模板中指定了查詢字符,此時#/login地址與#/login/100/sam兩個地址只有後一個會被匹配成功。能夠在組件對象的內部經過組件建立完成以後觸發的事件、使用$route.params獲取查詢字符串的值

<router-link to="/login/100/sam" >登陸</router-link>
var router = new VueRouter({   
    routes: [       
        { path: "/login/:id/:name", component: loginCom },  //這個路由模板只絕對匹配/login/id/name的路由請求,/login/100/sam/leo將不會被匹配
    ]
});

//當前組件被初始化時打印路由地址中的查詢字符
var login={
    template: "#loginTem",
    created: function () {
        console.log(this.$route.params.id);
    }
}

獲取路由地址 $route.path

$route.path獲取的地址不包括查詢字符串

methods: {
    btnClick: function () {
        console.log(this.$route.path);
    }
}
監聽路由

參考watch:vue-watch

子路由組件 

下圖中的帳戶是一個路由組件,而帳戶路由組件裏面又插入了登陸和註冊路由組件。

<div id="box">
    <router-link to="/account">帳戶</router-link>
    <router-view></router-view> //切換帳戶模塊和其它模塊的路由組件容器
</div>

<template id="tem">
    <div class="module-box">
        <p>帳戶模塊</p>
        <router-link to="/account/login">登陸</router-link>
        <router-link to="/account/register">註冊</router-link>
        <router-view></router-view> //切換帳戶模塊下的登陸和註冊模塊的子路由組件容器
    </div>
</template>

<template id="login">
    <div class="form-group">
        <label>
            用戶:<input type="text" class="form-control" />
        </label>
        <label>
            密碼:<input type="text" class="form-control" />
        </label>
        <button class="btn btn-primary">OK</button>
    </div>
</template>

<template id="register">
    <div class="form-group">
        <label>
            用戶:<input type="text" class="form-control" />
        </label>
        <label>
            密碼:<input type="text" class="form-control" />
        </label>
        <label>
            電郵:<input type="text" class="form-control" />
        </label>
        <button class="btn btn-primary">OK</button>
    </div>
</template>

</body>
</html>
<script>
    var router = new VueRouter({
        routes: [
            {
                path: "/account",
                component: { template: "#tem" },
                //在路由模板裏添加子路由模板
                children: [
                    { path: "login", component: { template: "#login" } },
                    { path: "register", component: { template: "#register" } }
                ]
            }
        ]
    });

    var vm = new Vue({
        el: "#box",
        data: {
            msg:"hello"
        },
        router:router
    });
</script>

注意若是一個路由組件裏嵌套了其它的路由組件,那麼必須在路由匹配規則的父規則裏使用children指定嵌套在父路由裏的子路由,那麼這種關係必須使用children指定,若是你把子路由匹配規則放在父路由規則的外面,那麼當你點擊router-link發起子路由請求後,父路由組件會被切換掉,看不見。也即你想在切換路由的時候父路由必須顯示出來,就必須指定children。只有指定了children屬性才使嵌套的路由組件成爲父子關係。

若是要讓頁面一加載就顯示其中某個子路由,能夠利用redirect實現

{
    path"/account",
    component{ template"#tem" },
    redirect"/account/login",
    children[
        { path: "login", component: { template: "#login" } },
        { path: "register", component: { template: "#register" } }
    ]
}

//帶查詢字符串的默認子路由
{
    path"/index",
    component{ template"#tem" },
    redirect"/index/product/1",
    children[
        { path: "product/:id", component: { template: "#product" } },
        { path: "photo", component: { template: "#photo" } }
    ]
}

子路由是在router-view中嵌套了另外一個router-view且它須要註冊到路由對象裏某個路由匹配規則中的children屬性中,經過點擊按鈕或超連接可讓父路由所包含的子路由顯示出來且不會把父路由組件給切換掉。

關於路由的總結

一般狀況下,一個頁面上只能有一個router-view,但能夠有多個router-link,不管在同一個頁面上的哪個router-link發起了路由請求、待路由匹配成功後都是將對應的路由組件插入到這個頁面上的那個惟一的router-view容器中。

路由組件和普通組件的結合使用

經典的top、left、right的css佈局中把頁面分紅了頂部、側邊欄和內容區域,若是用路由來實現,那麼當訪問根頁面的時候就須要render一個普通組件(index.vue)到index.html中,index.vue中把top直接作成一個固定的頂部banner,側邊欄則可使用普通組件(left.vue)做爲index.vue組件的普通子組件插入,而後右邊的內容區域(content)則經過left.vue的router-link的點擊發起路由請求進行切換不一樣的內容。因爲在index頁面上全部的路由連接發起的請求都是將對應的路由組件加載到同一個router-view(右邊content區域),這就符合一個頁面上只能有一個router-view的定義。若是你把left區域作成一個路由組件,那麼index.vue中就會出現兩個router-view,這樣就違背了一個頁面上只能有一個router-view的原則,這兩個router-view(即側邊欄和右邊內容區域)因爲它們各自都表明了一個路由請求,而一個瀏覽器地址欄卻只能發起一個路由請求,不可能同時發起兩個路由請求,因此不少時候咱們可能都須要用路由組件去結合普通組件達到目的。

index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title></title>   
</head>
<body>
    <div class="box"></div>
</body>
</html>
<script src="/bundle.js"></script>

index.vue

將側邊欄註冊爲index.vue的普通子組件

<template>
    <div class="index-box">
        <div class="header-box"></div>
        <div class="bottom-box">
            <left></left>    
            <router-view></router-view>
        </div>
    </div>
</template>
<script>
    import left from "./left.vue";

    export default {
        components: {
            left: left           
        }
    }
</script>

right1.vue

<template>
    <div class="right-box">
        <h1>卡俄斯</h1>
    </div>
</template>
<script>
    export default { }
</script>

right2.vue

<template>
    <div class="right-box">
        <h1>普羅米修斯</h1>
    </div>
</template>
<script>
    export default { }
</script>

main.js

main.js將index.vue渲染到index.html

import Vue from "vue";
import "./css/style.css";
import router from "./js/router";
import index from "./components/index.vue";

var vm = new Vue({
    el: ".box",    
    router: router,
    render: (c) => { return c(index); } //注意render方法並不會經過路由請求獲得index.vue,而是直接渲染了index.vue組件到index.html
});

router模板

import Vue from "vue";
import VueRouter from "vue-router";
import right1 from "../components/right1.vue";
import right2 from "../components/right2.vue";

Vue.use(VueRouter);

const router = new VueRouter({  
    routes: [
        { path: "/", redirect:"/index/right1" },
        { path: "/index/right1", component: right1 },
        { path: "/index/right2", component: right2 }
    ]
});
export default router;

路由組件組

一個頁面只能有一個惟一的router-view,若是想實現一個路由請求能渲染多個路由組件,則能夠爲router-view指定name屬性,而後在路由模板裏使用components(注意是複數)指定多個路由組件匹配同一個路由請求。這樣過程是:客戶端發起路由請求,路由對象開始匹配這個路由地址,它首先匹配瀏覽器的路由地址,而後進入匹配成功的路由模板,接着發現有components路由組件組的定義,它會根據conponents中定義的路由匹配名稱找到對應的多個路由組件一併返回給客戶端,也就是說router-view一旦定義了name,那麼整個路由匹配就會先匹配瀏覽器的路由地址,成功後再匹配components裏的路由組件,最後再返回給客戶端。因此,路由組件組的意思就是匹配一個路由地址返回多個路由組件。

<div id="box">
    <router-view></router-view//沒有指定name屬性的router-view在路由匹配成功後會把對應的組件插入這個路由組件
    <router-view name="left" class="left"></router-view> //指定name屬性,讓路由對象在components中查找對應的路由組件
    <router-view name="right" class="right"></router-view>
</div>

<script>
    var header = {
        template:"<h5>header</h5>"
    }

    var left = {
        template: "<h5>left</h5>"
    }

    var right = {
        template: "<h5>right</h5>"
    }

    var router = new VueRouter({
        routes: [
            {
                path: "/", components: { //當路由請求的是根目錄時,路由匹配成功後再也不返回某個單一的組件,而是返回多個由components指定的且與router-view的name相匹配的路由組件
                    default: header, //default默認返回header組件
                    left: left, //自定義指向left組件
                    right: right //自定義指向right組件
                }
            },
        ]
    });

    var vm = new Vue({
        el: "#box",
        data: {
            msg:"hello"
        },
        router:router
    });
</script>

子路由組件、子路由組件組的結合使用

但以上寫法沒法切換右邊內容區域,考慮改造,參考以下代碼來深刻理解路由組件的嵌套規則,先看下圖

圖片展現了路由組件嵌套後的效果,整個頁面分爲top和bottom,top是header元素,它是固定的一個div。bottom是一個路由組件,它匹配對根目錄的路由請求。bottom分爲側邊欄和右邊內容區域,側邊欄是一個普通的組件,將它註冊爲bottom路由組件的子組件,當頁面一加載就會顯示header和bottom,因爲側邊欄不是路由組件,因此它也會隨同bottom路由組件一塊兒顯示出來。接下來就是右邊內容區域,很明顯它是一個隨着導航連接進行切換的路由組件,因此能夠在bottom路由組件裏定義left側邊欄和一個右邊內容區域的router-view,右邊內容區域是屬於嵌套在bottom裏的子路由組件,因此再路由匹配中還須要使用children屬性來指定。如今思考一下,當點擊register後(看上圖),右邊內容區域並非只顯示一個路由組件,而是顯示了兩個,一個是register1,另外一個則是register2,這就須要兩個router-view才行,其中一個不須要設置name,將它用來展現默認的email和register1兩個路由組件,它們能夠隨着email和register兩個超連接的點擊而自動切換,而剩下一個register2怎麼辦呢?能夠把它放在默認的router-view的後面,給它指定一個name,因爲register1和register2隸屬於一個相同的路由地址,因此咱們能夠在路由模板中設置components對它們進行匹配。

index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title></title>   
    <style>
    </style>
</head>
<body>
    <div class="box">
        <div class="header-box"></div>
        <router-view></router-view> //用於顯示bottom路由組件
    </div>
</body>
</html>
<script src="/bundle.js"></script>

main.js

import Vue from "vue";
import router from "./js/router";

var vm = new Vue({
    el: ".box",    
    router: router   
});

bottom.vue

<template>
    <div class="bottom-box">
        <left class="left-box"></left>
        <div class="right-box">
            <router-view></router-view> //email、register1路由組件會插入這個容器
            <router-view name="register"></router-view> //register2路由組件會插入這個容器
        </div>
    </div>
</template>
<script>
    import left from "../components/left.vue";
    export default {
        components: {
            left: left
        }
    }
</script>

left.vue

left做爲bottom路由組件的普通子組件

<template>
    <div class="left-box">
        <ul>
            <li><router-link to="/index/email">email</router-link></li>
            <li><router-link to="/index/register">register</router-link></li>
        </ul>
    </div>
</template>
<script>
    export default { }
</script>

email.vue

bottom的子路由組件email.vue會根據路由請求顯示在bottom路由組件裏默認的router-view裏邊

<template>
    <div class="right-content0">
        <h1>email</h1>
    </div>
</template>
<script>
    export default { }
</script>

register1.vue

bottom的子路由組件register1.vue會根據路由請求顯示在bottom路由組件裏默認的router-view裏邊

<template>
    <div class="right-content1">
        <h1>register1</h1>
    </div>
</template>
<script>
    export default {}
</script>

register2.vue

bottom的子路由組件register2.vue會根據路由請求顯示在bottom路由組件裏命名的router-view裏邊

<template>
    <div class="right-content2">
        <h1>register2</h1>
    </div>
</template>
<script>
    export default {}
</script>

router模板

import Vue from "vue";
import VueRouter from "vue-router";
import bottom from "../components/bottom.vue";
import email from "../components/email.vue";
import register1 from "../components/register1.vue";
import register2 from "../components/register2.vue";

Vue.use(VueRouter);

const router = new VueRouter({  
    routes: [
        {
            path: "/",
            component: bottom, //路由根請求返回bottom組件插入到index.html的router-view裏面
            redirect:"/index/email",
            children: [
                { path: "/index/email", component: email }, //右邊內容區域默認顯示email組件
                {
                    path: "/index/register", //請求這個路由時返回兩個子路由組件
                    components: {
                        default: register1, //default:插入未命名的router-view中
                        register: register2  //插入命名的router-view中
                    }
                }
            ]
        }
    ]
});
export default router;
路由組件的動畫
與組件動畫是同樣的設置方式,但惟一不一樣點是不須要一個布爾值來控制顯示與隱藏,這個工做路是對象自動根據匹配的路由顯示相應的組件而隱藏了不須要的組件。
<transition mode="out-in">
        <router-view></router-view> 
</transition>
.v-enter,.v-leave-to{
    opacity:0;
    transform:translateX(150px);
}

.v-enter-active.v-leave-active {
    transition:all 0.5s ease;
}

 

Javascript - 學習總目錄 

相關文章
相關標籤/搜索