前端路由vue-router介紹

1、前端路由vue-router介紹

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

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

  vue vue-router 主要是用來作 單頁面應用(Single Page Application)html

一、爲何要作單頁面應用?

(1)傳統的開發方式

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

  用戶體驗很差。vue

(2)SPA單頁面應用

  SPA:Single Page Applicationjava

  錨點值改變後,不會馬上發送請求,而是在某個合適的時機,發送ajax請求,局部改變頁面中的數據。node

  頁面不馬上跳轉,用戶體驗好。react

 二、前端路由的實現原理

  前端路由:android

     1.錨點值監視; 2.ajax獲取動態的數據; 3.核心點是錨點值的改變;ajax

  前端中的 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 屬性修改錨部分。
  • 使用不一樣書籤導航到當前頁面(使用"後退" 或"前進"按鈕)
  • 點擊連接跳轉到書籤錨

三、根據不一樣錨點切換頁面效果

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

  

(2)點擊登陸頁面

  

(3)點擊註冊頁面

  

2、vue-router使用 

一、用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
03-vue-router@1.0.0 /Users/hqs/PycharmProjects/vue_study/03-vue-router
└── vue-router@3.0.1 

npm WARN 03-vue-router@1.0.0 No description
npm WARN 03-vue-router@1.0.0 No repository field.

  查看項目文件目錄:

  

二、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

  

  這種問題就是由於本身建立的router對象沒有被Vue實例化對象所使用:

new Vue({   // Vue實例化對象
    el:'#app',
    components:{
        App
    },
    router,   // router:router, 在key和value相同時能夠只寫一個
    template:`<App/>`   // 入口組件
});

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

  1)點擊前效果:

  

  能夠看到router-link默認會被渲染爲a標籤,to屬性默認會被渲染爲href屬性。

  2)點擊後效果:

  

(4)小結  

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

  

三、命名路由

  有時候,經過一個名稱來標識一個路由顯得更方便一些,特別是在連接一個路由,或者是執行一些跳轉的時候。你能夠在建立 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>
    `
};

四、總結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/>`
});

3、路由參數(範式)

  在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>

一、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對象
    }
};

  顯示效果以下:

  

二、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.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(路由配置信息)

四、配置路由對象方式

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

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

五、匹配路由

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>
    `
};

  訪問效果以下所示:

  

4、編程式導航 

  除了使用 <router-link> 建立 a 標籤來定義導航連接,咱們還能夠藉助 router 的實例方法,經過編寫代碼來實現。

一、編程式導航示例

  對上例作以下修改,再也不使用聲明式的<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訪問顯示效果:

  

  query訪問顯示效果:

  

二、router.push(location, onComplete?, onAbort?)

  注意:在 Vue 實例內部,你能夠經過 $router 訪問路由實例。所以你能夠調用 this.$router.push

  想要導航到不一樣的 URL,則使用 router.push 方法。這個方法會向 history 棧添加一個新的記錄,因此,當用戶點擊瀏覽器後退按鈕時,則回到以前的 URL。

  當你點擊 <router-link> 時,這個方法會在內部調用,因此說,點擊 <router-link :to="..."> 等同於調用 router.push(...)

   

  該方法的參數能夠是一個字符串路徑,或者一個描述地址的對象。例如:

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

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

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

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

  注意:若是提供了 pathparams 會被忽略,上述例子中的 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 來響應這個變化 (好比抓取用戶信息)

5、嵌套路由 

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

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

  藉助 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">

        // 嵌套路由:
        // 需求:進入首頁後,點擊音樂(/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>

二、注意要點

(1)以 / 開頭的嵌套路徑會被看成根路徑。 這讓你充分的使用嵌套組件而無須設置嵌套的路徑。

(2)children 配置就是像 routes 配置同樣的路由配置數組,因此呢,你能夠嵌套多層路由。

三、顯示效果

(1)頁面首頁默認顯示音樂 

  

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

  

四、嵌套路由警告處理

  

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

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>
    `,
};

  再次查看控制檯,警報解除:

  

6、動態路由匹配  

  咱們常常須要把某種模式匹配到的全部路由,全都映射到同個組件。例如,咱們有一個 User 組件,對於全部 ID 各不相同的用戶,都要使用這個組件來渲染。那麼,咱們能夠在 vue-router 的路由路徑中使用「動態路徑參數」(dynamic segment) 來達到這個效果。

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

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

一、動態路由匹配示例

<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)顯示效果及生命週期鉤子不重複調用

  初始狀態:

  

  點擊首頁,顯示alert:

  

  點擊確認後顯示:

  

  點擊前端:

   

  再點回安卓或首頁,頁面顯示會調整,但都再也不顯示alert。說明生命週期鉤子再也不運行。

二、響應路由參數的變化  

  前面已經說到當使用路由參數時,例如從 /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信息

  

(2)而後再點擊前端頁面,打印的to和from信息

  

(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;
        }
    }
}; 

  點擊顯示效果以下所示:

  

  也能夠看到組件沒有再次被銷燬或建立。

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

  <keep-alive>是Vue的內置組件,能在組件切換過程當中將狀態保留在內存中(緩存),防止重複渲染DOM。

(1)Props:

  • include:字符串或正則表達式。只有名稱匹配的組件會被緩存。
  • exclude:字符串或正則表達式。任何名稱匹配的組件都不會被緩存。
  • max:數字。最多能夠緩存多少組件實例。

(2)用法:

  <keep-alive> 包裹動態組件時,會緩存不活動的組件實例,而不是銷燬它們。和 <transition> 類似,<keep-alive> 是一個抽象組件:它自身不會渲染一個 DOM 元素,也不會出如今父組件鏈中

  當組件在 <keep-alive> 內被切換,它的 activated 和 deactivated 這兩個生命週期鉤子函數將會被對應執行。

  主要用於保留組件狀態或皮面從新渲染。

一、不使用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,切換頁面時都會執行生命週期操做:

  

  並且切換到沸點頁面,點擊「我是沸點」,能夠將字體變紅,可是切換到首頁再切換沸點時,又變黑色了。也說明了從新進行了建立銷燬

二、用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>
    `,
};

  顯示效果以下:

  

  能夠看到第一次點擊會建立和加載,但並無銷燬DOM,從首頁切換到沸點,仍保持爲紅色。

相關文章
相關標籤/搜索