天天看點

前端路由vue-router介紹

一、前端路由vue-router介紹

  Vue-Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度內建,讓建構單頁面應用變得易如反掌。包含的功能有:

  • 嵌套的路由/視圖表
  • 子產品化的、基于元件的路由配置
  • 路由參數、查詢、通配符
  • 基于 Vue.js 過渡系統的視圖過渡效果
  • 細粒度的導航控制
  • 帶有自動激活的 CSS class 的連結
  • HTML5 曆史模式或 hash 模式,在 IE9 中自動降級
  • 自定義的滾動條行為

  vue + vue-router 主要是用來做 單頁面應用(Single Page Application)。

1、為什麼要做單頁面應用?

(1)傳統的開發方式

  url改變後,立馬發送請求,響應整個頁面,有可能資源過多,傳統的開發會讓前端的頁面出現“白屏”。

  使用者體驗不好。

(2)SPA單頁面應用

  SPA:Single Page Application

  錨點值改變後,不會立刻發送請求,而是在某個合适的時機,發送ajax請求,局部改變頁面中的資料。

  頁面不立刻跳轉,使用者體驗好。

 2、前端路由的實作原理

  前端路由:

     1.錨點值監視; 2.ajax擷取動态的資料; 3.核心點是錨點值的改變;

  前端中的 vue/react/angular 都很适合做單頁面應用。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <a href="#/login">登入頁面</a>
    <a href="#/register">注冊頁面</a>
    <div id="app">
        
    </div>
    <script type="text/javascript">
        // 擷取div
        var oDiv = document.getElementById('app');

        window.onhashchange = function () {
            console.log(location.hash);
            // 根據不同的錨點值,對頁面不同的切換
            switch (location.hash) {
                case '#/login':
                    oDiv.innerHTML = '<h2>登入頁面</h2>';
                    break;
                case '#/register':
                    oDiv.innerHTML = '<h2>注冊頁面</h2>';
                    break;
                default:
                    // statements_def
                    break;
            }
        }
    </script>
</body>
</html>
      

(1)window.onhashchange介紹

  當一個視窗的 hash (URL中'#'後面的部分)改變時就會觸發 onhashchange 事件。

  onhashchange 事件在目前url的錨點部分(以'#'号為開始)發生改變時觸發。

  錨部分的執行個體:指定目前URL為http://www.example.com/test.htm#part2 - 這個 URL 中的錨部分為 #part2。

(2)onhashchange調用事件方法

  • 通過設定Location 對象 的 location.hash 或 location.href 屬性修改錨部分。
  • 使用不同書簽導航到目前頁面(使用"後退" 或"前進"按鈕)
  • 點選連結跳轉到書簽錨

3、根據不同錨點切換頁面效果

(1)初始頁面顯示如下:

  

前端路由vue-router介紹

(2)點選登入頁面

前端路由vue-router介紹

(3)點選注冊頁面

前端路由vue-router介紹

二、vue-router使用 

1、用NPM下載下傳安裝vue-router

(venv) MacBook-Pro:vue_study hqs$ cd 03-vue-router/
(venv) MacBook-Pro:03-vue-router hqs$ ls
01-前端路由實作原理.html                vue.js
(venv) MacBook-Pro:03-vue-router hqs$ npm init --yes
Wrote to /Users/hqs/PycharmProjects/vue_study/03-vue-router/package.json:

{
  "name": "03-vue-router",
  "version": "1.0.0",
  "description": "",
  "main": "vue.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

(venv) MacBook-Pro:03-vue-router hqs$ npm install vue-router -S
[email protected] /Users/hqs/PycharmProjects/vue_study/03-vue-router
└── [email protected] 

npm WARN [email protected] No description
npm WARN [email protected] No repository field.
      

  檢視項目檔案目錄:

前端路由vue-router介紹

2、vue-router應用執行個體

<body>
    <div id="app"></div>
    <script type="text/javascript" src="vue.js"></script>
    <!--1.引入vue-router的對象-->
    <script type="text/javascript" src="./node_modules/vue-router/dist/vue-router.js"></script>
    <!--全局的VueRouter對象 vue-router還提供了兩個全局的元件router-link / router-view-->
    <script type="text/javascript">
        // 2.讓Vue使用該VueRouter建立
        Vue.use(VueRouter);

        var Login = {      // 元件建立
            template:`
                <div>登入頁面</div>
            `
        };

        var Register = {   // 元件建立
            template:`
                <div>注冊頁面</div>
            `
        };

        // 3.建立一個路由對象
        var router = new VueRouter({
            // 配置路由對象
            routes:[
                {
                    path:'/login',   // login路由
                    component:Login
                },
                {
                    path:'/register',
                    component:Register
                }
            ]
        });

        var App = {   // App:入口元件
            // router-link預設會被渲染為a标簽,to屬性預設會被渲染為href屬性
            // router-view是路由元件的出口
            template:`
                <div>
                    <router-link to="/login">登入頁面</router-link>
                    <router-link to="/register">注冊頁面</router-link>
                    <router-view></router-view>
                </div>
            `
        };

        new Vue({   // Vue執行個體化對象
            el:'#app',
            components:{
                App
            },
            router,   // router:router, 在key和value相同時可以隻寫一個
            template:`<App/>`   // 入口元件
        });
    </script>
</body>      

注意要點:

(1)<router-link>元件和<router-view>元件

  全局的VueRouter對象 vue-router 還提供了兩個全局的元件router-link / router-view。

<router-link>

 元件支援使用者在具有路由功能的應用中 (點選) 導航。 通過 

to

 屬性指定目标位址,預設渲染成帶有正确連結的 

<a>

 标簽,可以通過配置 

tag

 屬性生成别的标簽.。另外,當目标路由成功激活時,連結元素自動設定一個表示激活的 CSS 類名。

<router-view>

 元件是一個 functional 元件,渲染路徑比對到的視圖元件,是所有路由元件的出口。

<router-view>

 渲染的元件還可以内嵌自己的 

<router-view>

,根據嵌套路徑,渲染嵌套元件。

var App = {
    // router-link預設會被渲染為a标簽 to屬性預設會被渲染為href屬性
    // router-view是路由元件的出口
    template:`
        <div>
            <router-link to="/login">登入頁面</router-link>
            <router-link to="/register">注冊頁面</router-link>

            <router-view></router-view>
        </div>
    `
};      

(2)報錯Cannot read property 'matched' of undefined

前端路由vue-router介紹

  這種問題就是因為自己建立的router對象沒有被Vue執行個體化對象所使用:

new Vue({   // Vue執行個體化對象
    el:'#app',
    components:{
        App
    },
    router,   // router:router, 在key和value相同時可以隻寫一個
    template:`<App/>`   // 入口元件
});      

(3)頁面通過router-view渲染

  1)點選前效果:

前端路由vue-router介紹

  可以看到router-link預設會被渲染為a标簽,to屬性預設會被渲染為href屬性。

  2)點選後效果:

前端路由vue-router介紹

(4)小結  

  當你在頁面通路login時,router-link對應着的路徑是'/login',加載對應的component元件:Login,component元件找一個出口渲染出來:router-view。

前端路由vue-router介紹

3、命名路由

  有時候,通過一個名稱來辨別一個路由顯得更友善一些,特别是在連結一個路由,或者是執行一些跳轉的時候。你可以在建立 Router 執行個體的時候,在 

routes

 配置中給某個路由設定名稱。

  給目前的配置路由資訊對象設定name屬性。

  對上面代碼做如下修改:

var router = new VueRouter({
    // 配置路由對象
    routes:[
        {
            path:'/login',
            name:'login',      // 設定路由名稱
            component:Login
        },
        {
            path:'/register',
            name:'register',   // 設定路由名稱
            component:Register
        }
    ]
});

var App = {
    // 不使用to屬性通路路由,改用動态命名路由綁定
    // 要連結到一個命名路由,可以給 router-link 的 to 屬性傳一個對象:
    template:`
        <div>
            <router-link :to="{name:'login'}">登入頁面</router-link>
            <router-link :to="{name:'register'}">注冊頁面</router-link>
            <router-view></router-view>
        </div>
    `
};      

4、總結Vue Router流程

(1)引入vue-router對象子產品

<script type="text/javascript" src="vue.js"></script>
<!--引入vue-router的對象-->
<script type="text/javascript" src="./node_modules/vue-router/dist/vue-router.js"></script>      

  該子產品預設會抛出一個VueRouter對象,另外還有兩個全局的元件router-link和router-view。

(2)讓Vue使用該VueRouter建立

// 如果使用子產品化機制程式設計,導入Vue和VueRouter,要調用Vue.use(VueRouter)

<script type="text/javascript">

    // 讓Vue使用該VueRouter建立
    Vue.use(VueRouter);
    
    // 代碼省略
</script>
      

(3)建立路由對象

// 3.建立一個路由對象
var router = new VueRouter({
    // 配置路由對象
    routes:[
        {
            path:'/login',
            name:'login',      // 設定路由名稱
            component:Login
        },
        {
            path:'/register',
            name:'register',   // 設定路由名稱
            component:Register
        }
    ]
});
      

(4)路由對象挂載到vue執行個體化對象中

var App = {
    // 不使用to屬性通路路由,改用動态命名路由綁定
    // 要連結到一個命名路由,可以給 router-link 的 to 屬性傳一個對象:
    template:`
        <div>
            <router-link :to="{name:'login'}">登入頁面</router-link>
            <router-link :to="{name:'register'}">注冊頁面</router-link>
            <router-view></router-view>
        </div>
    `
};

new Vue({
    el:'#app',
    components:{
        App
    },
    router,   // router:router, 在key和value相同時可以隻寫一個
    template:`<App/>`
});      

三、路由參數(範式)

  在vue-router路由中,傳參方式一般分兩種。如下所示:

(1)xxx.html#/user/1            params 動态路由參數
(2)xxx.html#/user?userId=2     query 查詢      

  示例代碼如下所示:

<body>
    <div id="app"></div>
    <script type="text/javascript" src="vue.js"></script>
    <!--1.引入vue-router的對象-->
    <script type="text/javascript" src="./node_modules/vue-router/dist/vue-router.js"></script>
    <!--全局的VueRouter對象 vue-router還提供了兩個全局的元件router-link / router-view-->
    <script type="text/javascript">
        // 路由範式
        //(1)xxx.html#/user/1   params 動态路由參數
        //(2)xxx.html#/user?userId=2   query 查詢

        // 2.讓Vue使用該VueRouter建立
        Vue.use(VueRouter);

        var UserParams = {
            template:`
                <div>我是使用者1</div>
            `,
            created(){
                // 接收參數
                console.log(this.$route);   // 其中包含params屬性
                console.log(this.$route.params.userId);  // 輸出:1
                // 傳參,發送ajax請求
                console.log(this.$router);  // VueRouter對象
            }
        };

        var UserQuery = {
            template:`
                <div>我是使用者2</div>
            `,
            created(){
                // 接收參數
                console.log(this.$route);  // 包含query屬性,query: {userId: "2"}
                console.log(this.$route.query.userId);  // 輸出:2

                // 傳參,發送ajax請求
                console.log(this.$router);  // VueRouter對象
            }
        };

        // 3.建立一個路由對象
        var router = new VueRouter({
            // 配置路由對象
            routes:[
                {
                    path:'/user/:userId',  // params形式,動态路由參數,以冒号開頭
                    name:'userp',      // 設定路由名稱
                    component:UserParams
                },
                {
                    path:'/user',
                    name:'userq',   // 設定路由名稱
                    component:UserQuery
                }
            ]
        });

        var App = {
            // 不使用to屬性通路路由,改用動态命名路由綁定.要連結到一個命名路由,可以給 router-link 的 to 屬性傳一個對象
            // 路由比對,query是查詢操作
            template: `
                <div>
                    <router-link :to="{name:'userp', params:{userId:1}}">使用者1</router-link>
                    <router-link :to="{name:'userq', query:{userId:2}}">使用者2</router-link>
                    <router-view></router-view>
                </div>
            `
        };

        new Vue({
            el:'#app',
            components:{
                App
            },
            router,   // router:router, 在key和value相同時可以隻寫一個
            template:`<App/>`
        });
    </script>
</body>      

1、query方式傳參和接收參數

  利用$route.query對象的Get方式傳參,與http的get方式一樣,會将參數暴露到位址欄。

var UserQuery = {
    template:`
        <div>我是使用者2</div>
    `,
    created(){
        // 接收參數
        console.log(this.$route);  // 包含query屬性,query: {userId: "2"}
        console.log(this.$route.query.userId);  // 輸出:2

        // 傳參,發送ajax請求
        console.log(this.$router);  // VueRouter對象
    }
};      

  顯示效果如下:

前端路由vue-router介紹

2、params方式傳參和接收參數

  利用$route.params對象的Post方式傳參,該方式具有一定限制,必須通過路徑傳參方式。

var UserParams = {
    template:`
        <div>我是使用者1</div>
    `,
    created(){
        // 接收參數
        console.log(this.$route);   // 其中包含params屬性
        console.log(this.$route.params.userId);  // 輸出:1
        // 傳參,發送ajax請求
        console.log(this.$router);  // VueRouter對象
    }
};
      

  顯示效果如下所示:

前端路由vue-router介紹

3、源碼分析

// vue-router.js檔案558行到564行
  Object.defineProperty(Vue.prototype, '$router', {
    get: function get () { return this._routerRoot._router }
  });

  Object.defineProperty(Vue.prototype, '$route', {
    get: function get () { return this._routerRoot._route }
  });
      

  相當于給vue執行個體化對象添加了兩個屬性$router(VueRouter)和$route(路由配置資訊)。

4、配置路由對象方式

// 3.建立一個路由對象
var router = new VueRouter({
    // 配置路由對象
    routes:[
        {
            path:'/user/:userId',  // params形式,動态路由參數,以冒号開頭
            name:'userp',      // 設定路由名稱
            component:UserParams
        },
        {
            path:'/user',
            name:'userq',   // 設定路由名稱
            component:UserQuery
        }
    ]
});
      

  注意params形式,是配置動态路由參數,要以冒号開頭。

5、比對路由

var App = {
    // 不使用to屬性通路路由,改用動态命名路由綁定.要連結到一個命名路由,可以給 router-link 的 to 屬性傳一個對象
    template:`
        <div>
            <router-link :to="{name:'userp', params:{userId:1}}">使用者1</router-link>
            <router-link :to="{name:'userq', query:{userId:2}}">使用者2</router-link>
            <router-view></router-view>
        </div>
    `
};
      

  通路效果如下所示:

前端路由vue-router介紹

四、程式設計式導航 

  除了使用 

<router-link>

 建立 a 标簽來定義導航連結,我們還可以借助 router 的執行個體方法,通過編寫代碼來實作。

1、程式設計式導航示例

  對上例做如下修改,不再使用聲明式的<router-link :to='...'>,改為使用程式設計式:router.push(...)

var App = {
    // 不使用to屬性通路路由,改用動态命名路由綁定.要連結到一個命名路由,可以給 router-link 的 to 屬性傳一個對象
    template:`
        <div>
            <button @click="paramsHandler">使用者1</button>
            <button @click="queryHandler">使用者2</button>

            <router-view></router-view>
        </div>
    `,
    methods:{
        paramsHandler(){
            // 程式設計式導航
            this.$router.push({ name: 'userp', params: { userId: 123 }})
        },
        queryHandler(){
            this.$router.push({ name: 'userq', query: {userId: 3221} })
        }
    }
};
      

  params通路顯示效果:

前端路由vue-router介紹

  query通路顯示效果:

前端路由vue-router介紹

2、router.push(

location, onComplete?, onAbort?

)

  注意:在 Vue 執行個體内部,你可以通過 

$router

 通路路由執行個體。是以你可以調用 

this.$router.push

  想要導航到不同的 URL,則使用 

router.push

 方法。這個方法會向 history 棧添加一個新的記錄,是以,當使用者點選浏覽器後退按鈕時,則回到之前的 URL。

  當你點選 

<router-link>

 時,這個方法會在内部調用,是以說,點選 

<router-link :to="...">

 等同于調用 

router.push(...)

   

前端路由vue-router介紹

  該方法的參數可以是一個字元串路徑,或者一個描述位址的對象。例如:

// 字元串
router.push('home')

// 對象
router.push({ path: 'home' })

// 命名的路由
router.push({ name: 'user', params: { userId: 123 }})

// 帶查詢參數,變成 /register?plan=private
router.push({ path: 'register', query: { plan: 'private' }})
      

  注意:如果提供了 

path

params

 會被忽略,上述例子中的 

query

 并不屬于這種情況。取而代之的是下面例子的做法,你需要提供路由的 

name

 或手寫完整的帶有參數的 

path

const userId = 123
router.push({ name: 'user', params: { userId }}) // -> /user/123
router.push({ path: `/user/${userId}` }) // -> /user/123
// 這裡的 params 不生效
router.push({ path: '/user', params: { userId }}) // -> /user
      

  同樣的規則也适用于 

router-link

 元件的 

to

 屬性。

  在 2.2.0+,可選的在 

router.push

 或 

router.replace

 中提供 

onComplete

 和 

onAbort

 回調作為第二個和第三個參數。這些回調将會在導航成功完成 (在所有的異步鈎子被解析之後) 或終止 (導航到相同的路由、或在目前導航完成之前導航到另一個不同的路由) 的時候進行相應的調用。

  注意:如果目的地和目前路由相同,隻有參數發生了改變 (比如從一個使用者資料到另一個 

/users/1

 -> 

/users/2

),你需要使用 

beforeRouteUpdate

 來響應這個變化 (比如抓取使用者資訊)

五、嵌套路由 

  實際生活中的應用界面,通常由多層嵌套的元件組合而成。同樣地,URL 中各段動态路徑也按某種結構對應嵌套的各層元件,例如: 

/user/foo/profile                     /user/foo/posts
+------------------+                  +-----------------+
| User             |                  | User            |
| +--------------+ |                  | +-------------+ |
| | Profile      | |  +------------>  | | Posts       | |
| |              | |                  | |             | |
| +--------------+ |                  | +-------------+ |
+------------------+                  +-----------------+      

  借助 

vue-router

,使用嵌套路由配置,就可以很簡單地表達這種關系。

1、嵌套路由示例

<body>
    <div id="app"></div>
    <script type="text/javascript" src="vue.js"></script>
    <!--1.引入vue-router的對象-->
    <script type="text/javascript" src="./node_modules/vue-router/dist/vue-router.js"></script>
    <!--全局的VueRouter對象 vue-router還提供了兩個全局的元件router-link / router-view-->
    <script type="text/javascript">

        // 嵌套路由:
        // 需求:進入首頁後,點選音樂(/home/music) 電影(/home/movie)

        // 2.讓Vue使用該VueRouter建立
        Vue.use(VueRouter);

        var Home = {
            // 子路由出口
            template:`
                <div>
                    <br/>
                    <router-link to="/home/music">音樂</router-link>
                    <router-link to="/home/movie">電影</router-link>

                    <router-view></router-view>
                </div>
            `
        };

        var Music = {
            template:`
                <div>我是音樂</div>
            `
        };

        var Movie = {
            template:`
                <div>我是電影</div>
            `
        };

        // 3.建立一個路由對象
        var router = new VueRouter({
            // 配置路由對象
            routes:[
                {
                    path:'/',
                    redirect:'home'
                    // redirect:{name:'home'}   // 指令路由的方式
                },
                {
                    path:'/home',  // params形式,動态路由參數,以冒号開頭
                    name:'home',      // 設定路由名稱
                    component:Home,
                    children:[
                        // 動态路由比對表示你的子元件中的結構是不同的

                        // 當通路/home元件時,Home元件的出口是不會渲染任何内容的,
                        // 這是因為沒有比對到合适的子路由
                        {
                            path:'',  // 通路空字元串就表示通路/home了
                            component:Music   // 預設加載孩子元件Music
                        },
                        {
                            path:'music',  // 自己會預設去拼接斜杠
                            component:Music  // 對應加載的元件
                            // children:  // 可以繼續配置三層路由
                        },
                        {
                            path:'movie',  // 自己會預設去拼接斜杠
                            component:Movie  // 對應加載的元件
                        }
                    ]
                },
            ]
        });

        var App = {
            // 路由出口
            template:`
                <div>
                    <router-link :to="{name:'home'}">首頁</router-link>

                    <router-view></router-view>
                </div>
            `,
        };

        new Vue({
            el:'#app',
            components:{
                App
            },
            router,   // router:router, 在key和value相同時可以隻寫一個
            template:`<App/>`
        });
    </script>
</body>
      

2、注意要點

(1)以 

/

 開頭的嵌套路徑會被當作根路徑。 這讓你充分的使用嵌套元件而無須設定嵌套的路徑。

(2)children

 配置就是像 

routes

 配置一樣的路由配置數組,是以呢,你可以嵌套多層路由。

3、顯示效果

(1)頁面首頁預設顯示音樂 

前端路由vue-router介紹

(2)點選切換到電影頁面

前端路由vue-router介紹

4、嵌套路由警告處理

前端路由vue-router介紹

  這個警告的意思是:當父路由有子路由時,不允許子路由中有命名路由。是以對代碼做如下調整

var router = new VueRouter({
    // 配置路由對象
    routes:[
        {
            path:'/',
            redirect:'home'
            // redirect:{name:'home'}   // 指令路由的方式
        },
        {
            path:'/home',  // params形式,動态路由參數,以冒号開頭
            // name:'home',      // 設定路由名稱
            component:Home,
            children:[
                // 動态路由比對表示你的子元件中的結構是不同的

                // 當通路/home元件時,Home元件的出口是不會渲染任何内容的,
                // 這是因為沒有比對到合适的子路由
                {
                    path:'',  // 通路空字元串就表示通路/home了
                    component:Music   // 預設加載孩子元件Music
                },
                {
                    path:'music',  // 自己會預設去拼接斜杠
                    component:Music  // 對應加載的元件
                    // children:  // 可以繼續配置三層路由
                },
                {
                    path:'movie',  // 自己會預設去拼接斜杠
                    component:Movie  // 對應加載的元件
                }
            ]
        },
    ]
});

var App = {
    // 路由出口
    template:`
        <div>
            <!--<router-link :to="{name:'home'}">首頁</router-link>-->
            <router-link to="/home">首頁</router-link>
            <router-view></router-view>
        </div>
    `,
};
      

  再次檢視控制台,警報解除:

前端路由vue-router介紹

六、動态路由比對  

  我們經常需要把某種模式比對到的所有路由,全都映射到同個元件。例如,我們有一個 

User

 元件,對于所有 ID 各不相同的使用者,都要使用這個元件來渲染。那麼,我們可以在 

vue-router

 的路由路徑中使用“動态路徑參數”(dynamic segment) 來達到這個效果。

const User = {
    template: '<div>User</div>'
}

const router = new VueRouter({
    routes: [
        // 動态路徑參數 以冒号開頭
        { path: '/user/:id', component: User }
    ]
})      

1、動态路由比對示例

<body>
    <div id="app"></div>
    <script type="text/javascript" src="vue.js"></script>
    <!--1.引入vue-router的對象-->
    <script type="text/javascript" src="./node_modules/vue-router/dist/vue-router.js"></script>
    <!--全局的VueRouter對象 vue-router還提供了兩個全局的元件router-link / router-view-->
    <script type="text/javascript">
        // 2.讓Vue使用該VueRouter建立
        Vue.use(VueRouter);

        var Timeline = {
            template:`
                <div>
                    <router-link :to="{name:'comDesc', params:{id:'android'}}">Android</router-link>
                    <router-link :to="{name:'comDesc', params:{id:'frontend'}}">前端</router-link>
                    <router-view></router-view>
                </div>
            `
        };

        var Pins = {
            template:`
                <div>
                    我是沸點
                </div>
            `
        };

        // 共同的子元件
        var ComDesc = {
            data(){
                return{
                    msg:''
                }
            },
            template:`
                <div>
                    我是{{msg}}
                </div>
            `,
            created(){   // 生命周期方法
                alert(1);
                this.msg = '安卓';
            }
        };

        // 3.建立一個路由對象
        var router = new VueRouter({
            // 配置路由對象
            routes:[
                // 動态路由參數以冒号開頭
                {
                    path:'/timeline',
                    component:Timeline,
                    children:[
                        {
                            path:"",
                            component:ComDesc  // 通路Timeline時通路共同元件ComDesc
                        },
                        {
                            path:'/timeline/:id',
                            name:'comDesc',
                            component:ComDesc  // 通路子動态路由時,也加載共同元件ComDesc
                        }

                    ]
                },
                {
                    path:'/pins',
                    component:Pins
                }
            ]
        });

        var App = {
            // 路由出口
            template:`
                <div>
                    <router-link to="/timeline">首頁</router-link>
                    <router-link to="/pins">沸點</router-link>
                    <router-view></router-view>
                </div>
            `,
        };

        new Vue({
            el:'#app',
            components:{
                App
            },
            router,   // router:router, 在key和value相同時可以隻寫一個
            template:`<App/>`
        });
    </script>
</body>
      

(1)路由映射到公共路由

var router = new VueRouter({
    // 配置路由對象
    routes:[
        // 動态路由參數以冒号開頭
        {
            path:'/timeline',
            component:Timeline,
            children:[
                {
                    path:"",
                    component:ComDesc  // 通路Timeline時通路共同元件ComDesc
                },
                {
                    path:'/timeline/:id',
                    name:'comDesc',
                    component:ComDesc  // 通路子動态路由時,也加載共同元件ComDesc
                }

            ]
        },
        {
            path:'/pins',
            component:Pins
        }
    ]
});      

  /timeline/android和/timeline/frontend都将映射相同的路由。

  一個“路徑參數”使用冒号 

:

 标記。當比對到一個路由時,參數值會被設定到 

this.$route.params

,可以在每個元件内使用。

(2)元件執行個體複用

  當使用路由參數時,例如從 

/user/foo

 導航到 

/user/bar

,原來的元件執行個體會被複用。因為兩個路由都渲染同個元件,比起銷毀再建立,複用則顯得更加高效。不過,這也意味着元件的生命周期鈎子不會再被調用。

// 共同的子元件
var ComDesc = {
    data(){
        return{
            msg:''
        }
    },
    template:`
        <div>
            我是{{msg}}
        </div>
    `,
    created(){   // 生命周期方法
        alert(1);
        this.msg = '安卓';
    }
};
      

(3)顯示效果及生命周期鈎子不重複調用

  初始狀态:

前端路由vue-router介紹

  點選首頁,顯示alert:

前端路由vue-router介紹

  點選确認後顯示:

前端路由vue-router介紹

  點選前端:

   

前端路由vue-router介紹

  再點回安卓或首頁,頁面顯示會調整,但都不再顯示alert。說明生命周期鈎子不再運作。

2、響應路由參數的變化  

  前面已經說到當使用路由參數時,例如從 

/user/foo

/user/bar

  複用元件時,想對路由參數的變化作出響應的話,你可以簡單地 watch (監測變化) 

$route

對象:

// 共同子元件
var ComDesc = {
    data(){
        return{
            msg:''
        }
    },
    template:`
        <div>
            我是{{msg}}
        </div>
    `,
    created(){   // 生命周期方法
        // alert(1);
        // this.msg = '安卓';
    },
    watch:{
        '$route' (to, from) {
            // 對路由變化作出響應...
            console.log(to);
            console.log(from);
        }
    }
};
      

(1)點選安卓頁面,列印出的to和from資訊

前端路由vue-router介紹

(2)然後再點選前端頁面,列印的to和from資訊

前端路由vue-router介紹

(3)直接渲染

var ComDesc = {
    data(){
        return{
            msg:''
        }
    },
    template:`
        <div>
            我是{{msg}}
        </div>
    `,
    created(){   // 生命周期方法
        // alert(1);
        // this.msg = 'android';
    },
    watch:{
        '$route' (to, from) {
            // 對路由變化作出響應...
            console.log(to);
            console.log(from);

            // 直接渲染
            this.msg = to.params.id;
        }
    }
}; 
      

  點選顯示效果如下所示:

前端路由vue-router介紹

  也可以看到元件沒有再次被銷毀或建立。

七、keep-alive在路由中的使用

<keep-alive>

是Vue的内置元件,能在元件切換過程中将狀态保留在記憶體中(緩存),防止重複渲染DOM。

(1)Props:

  • include:字元串或正規表達式。隻有名稱比對的元件會被緩存。
  • exclude:字元串或正規表達式。任何名稱比對的元件都不會被緩存。
  • max:數字。最多可以緩存多少元件執行個體。

(2)用法:

  <keep-alive>

 包裹動态元件時,會緩存不活動的元件執行個體,而不是銷毀它們。和 

<transition>

 相似,

<keep-alive>

 是一個抽象元件:它自身不會渲染一個 DOM 元素,也不會出現在父元件鍊中。

  當元件在 

<keep-alive>

 内被切換,它的 

activated

deactivated

 這兩個生命周期鈎子函數将會被對應執行。

  主要用于保留元件狀态或皮面重新渲染。

1、不使用keep-alive切換頁面

<script type="text/javascript">
    // 2.讓Vue使用該VueRouter建立
    Vue.use(VueRouter);

    var Timeline = {
        template:`
            <div>
                我是首頁
            </div>
        `,
        created(){
            console.log('首頁元件建立了');
        },
        mounted(){
            console.log('首頁元件DOM加載了');
        },
        destroyed(){
            console.log('首頁銷毀了');
        }
    };

    var Pins = {
        template:`
            <div>
                <h3 @click="clickHandler">我是沸點</h3>
            </div>
        `,
        methods:{
            clickHandler(e){
                e.target.style.color = 'red';
            }
        },
        created(){
            console.log('沸點元件建立了');
        },
        mounted(){
            console.log('沸點元件DOM加載了');
        },
        destroyed(){
            console.log('沸點銷毀了');
    };

    // 3.建立一個路由對象
    var router = new VueRouter({
        // 配置路由對象
        routes:[
            // 動态路由參數以冒号開頭
            {
                path:'/timeline',
                component:Timeline,
            },
            {
                path:'/pins',
                name:'pins',
                component:Pins
            }
        ]
    });

    var App = {
        // keep-alive元件保持緩存,把router-view渲染的出口緩存起來
        template:`
            <div>
                <router-link to="/timeline">首頁</router-link>
                <router-link to="/pins">沸點</router-link>

                <router-view></router-view>
            </div>
        `,
    };

    new Vue({
        el:'#app',
        components:{
            App
        },
        router,   // router:router, 在key和value相同時可以隻寫一個
        template:`<App/>`
    });
</script>
      

  此時還沒有使用keep-alive,切換頁面時都會執行生命周期操作:

前端路由vue-router介紹

  而且切換到沸點頁面,點選“我是沸點”,可以将字型變紅,但是切換到首頁再切換沸點時,又變黑色了。也說明了重新進行了建立銷毀。

2、用keep-alive元件把router-view渲染的出口緩存起來

  注意:

<keep-alive>

 是用在其一個直屬的子元件被開關的情形。如果你在其中有 

v-for

 則不會工作。如果有上述的多個條件性的子元素,

<keep-alive>

 要求同時隻有一個子元素被渲染。

var App = {
    // keep-alive元件保持緩存,把router-view渲染的出口緩存起來
    template:`
        <div>
            <router-link to="/timeline">首頁</router-link>
            <router-link to="/pins">沸點</router-link>

            <keep-alive>
                <router-view></router-view>
            </keep-alive>
        </div>
    `,
};
      
前端路由vue-router介紹

  可以看到第一次點選會建立和加載,但并沒有銷毀DOM,從首頁切換到沸點,仍保持為紅色。