1. 程式人生 > >20181206——Vuerouter真的最後一次了

20181206——Vuerouter真的最後一次了

執行過程:當用戶點選 router-link 標籤時,會去尋找它的 to 屬性, 它的 to 屬性和 js 中配置的路徑{ path:
‘/home’, component: Home} path 一一對應,從而找到了匹配的元件, 最後把元件渲染到
標籤所在的地方。所有的這些實現才是基於hash 實現的。

很經典的這句話,
讀完就懂

Vue-Router
 路由,其實就是指向的意思,當我點選頁面上的home按鈕時,頁面中就要顯示home的內容,如果點選頁面上的about 按鈕,頁面中就要顯示about 的內容。Home按鈕 => home 內容, about按鈕 => about 內容,也可以說是一種對映. 所以在頁面上有兩個部分,一個是點選部分,一個是點選之後,顯示內容的部分。
 路由中有三個基本的概念 route, routes, router。


 route,它是一條路由,由這個英文單詞也可以看出來,它是單數, Home按鈕 => home內容, 這是一條route, about按鈕 => about 內容, 這是另一條路由。
  routes 是一組路由,把上面的每一條路由組合起來,形成一個數組。[{home 按鈕 =>home內容 }, { about按鈕 => about 內容}]
  router 是一個機制,相當於一個管理者,它來管理路由。因為routes 只是定義了一組路由,它放在哪裡是靜止的,當真正來了請求,怎麼辦? 就是當用戶點選home 按鈕的時候,怎麼辦?這時router 就起作用了,它到routes 中去查詢,去找到對應的 home 內容,所以頁面中就顯示了 home 內容。
  客戶端中的路由,實際上就是dom 元素的顯示和隱藏。當頁面中顯示home 內容的時候,about 中的內容全部隱藏,反之也是一樣。客戶端路由有兩種實現方式:基於hash 和基於html5 history api.
在vue中實現路由還是相對簡單的。因為我們頁面中所有內容都是元件化的,我們只要把路徑和元件對應起來就可以了,然後在頁面中把元件渲染出來。

頁面實現(html模版中)

在vue-router中, 我們看到它定義了兩個標籤<router-link> 和<router-view>來對應點選和顯示部分。<router-link> 就是定義頁面中點選的部分,<router-view> 定義顯示部分,就是點選後,區配的內容顯示在什麼地方。所以 <router-link> 還有一個非常重要的屬性 to,定義點選之後,要到哪裡去, 如:<router-link  to="/home">Home</router-link>

js 中配置路由

首先要定義route, 一條路由的實現。它是一個物件,由兩個部分組成: path和component. path 指路徑,component 指的是元件。如:{path:’/home’, component: home}

我們這裡有兩條路由,組成一個routes:

const routes = [
  { path: '/home', component: Home },
  { path: '/about', component: About }
]

最後建立router 對路由進行管理,它是由建構函式 new vueRouter() 建立,接受routes 引數。

const router = new VueRouter({
      routes // routes: routes 的簡寫
})

配置完成後,把router 例項注入到 vue 根例項中,就可以使用路由了

const app = new Vue({
  router
}).$mount('#app')

執行過程:當用戶點選 router-link 標籤時,會去尋找它的 to 屬性, 它的 to 屬性和 js 中配置的路徑{ path: ‘/home’, component: Home} path 一一對應,從而找到了匹配的元件, 最後把元件渲染到 <router-view> 標籤所在的地方。所有的這些實現才是基於hash 實現的。

vue-cli 建立一個專案體驗一下, 當然不要忘記安裝vue-router

<template>
    <div>
        <h1>home</h1>
        <p>{{msg}}</p>
    </div>
</template>
<script>
    export default {
        data () {
            return {
                msg: "我是home 元件"
            }
        }
    }
</script>
<template>
    <div>
        <h1>about</h1>
        <p>{{aboutMsg}}</p>
    </div>
</template>
<script>
    export default {
        data () {
            return {
                aboutMsg: '我是about元件'
            }
        }
    }
</script>

App.vue

<template>
  <div id="app">
    <img src="./assets/logo.png">
    <header>
    <!-- router-link 定義點選後導航到哪個路徑下 -->
      <router-link to="/home">Home</router-link>
      <router-link to="/about">About</router-link>
    </header>
    <!-- 對應的元件內容渲染到router-view中 -->
    <router-view></router-view>   
  </div>
</template>

<script>
export default {
  
}
</script>

router

import Vue from "vue";
import VueRouter from "vue-router";

// 引入元件
import home from "./home.vue";
import about from "./about.vue";

// 要告訴 vue 使用 vueRouter
Vue.use(VueRouter);

const routes = [
    {
        path:"/home",
        component: home
    },
    {
        path: "/about",
        component: about
    }
]

var router =  new VueRouter({
    routes
})
export default router;

把路由注入到根例項中,啟動路由。這裡其實還有一種方法,就像vuex store 注入到根例項中一樣,我們也可以把vueRouter 直接注入到根例項中。在main.js中引入路由,注入到根例項中。

import Vue from 'vue'
import App from './App.vue'

// 引入路由
import router from "./router.js"    // import router 的router 一定要小寫, 不要寫成Router, 否則報 can't match的報錯
new Vue({
  el: '#app',
  router,  // 注入到根例項中
  render: h => h(App)
})

這時點選頁面上的home 和about 可以看到元件來回切換。但是有一個問題,當首次進入頁面的時候,頁面中並沒有顯示任何內容。這是因為首次進入頁面時,它的路徑是 ‘/’,我們並沒有給這個路徑做相應的配置。一般,頁面一載入進來都會顯示home頁面,我們也要把這個路徑指向home元件。但是如果我們寫{ path: ‘/’, component: Home },vue 會報錯,因為兩條路徑卻指向同一個方向。這怎麼辦?這需要重定向,所謂重定向,就是重新給它指定一個方向,它本來是訪問 / 路徑,我們重新指向‘/home’, 它就相當於訪問 ‘/home’, 相應地, home元件就會顯示到頁面上。vueRouter中用 redirect 來定義重定向。

const routes = [
    {
        path:"/home",
        component: home
    },
    {
        path: "/about",
        component: about
    },
    // 重定向
    {
        path: '/', 
        redirect: '/home' 
    }
]

重定向真的挺重要的,相當於path’/'的直接跳轉到home

動態路由
上面我們定義的路由,都是嚴格匹配的,只有router-link 中的to屬性和 js 中一條路由route中 path 一模一樣,才能顯示相應的元件component. 但有時現實卻不是這樣的,當我們去訪問網站並登入成功後,它會顯示 歡迎你,+ 你的名字。不同的使用者登入, 只是顯示“你的名字” 部分不同,其它部分是一樣的。這就表示,它是一個元件,假設是user元件。不同的使用者(就是使用者的id不同),它都會導航到同一個user 元件中。這樣我們在配置路由的時候,就不能寫死, 就是路由中的path屬性,不能寫死,那要怎麼設定? 導航到 user 元件,路徑中肯定有user, id 不同,那就給路徑一個動態部分來匹配不同的id. 在vue-router中,動態部分 以 : 開頭,那麼路徑就變成了 /user/:id, 這條路由就可以這麼寫: { path:"/user/:id", component: user }.

我們定義一個user元件(自己隨便寫一個就好了),頁面中再新增兩個router-link 用於導航, 最後router.js中新增路由配置,來體驗一下

app.vue 中新增兩個router-link:

<template>
  <div id="app">
    <img src="./assets/logo.png">
    <header>
      <router-link to="/home">Home</router-link>
      <router-link to="/about">About</router-link>
     <!--  增加兩個到user元件的導航,可以看到這裡使用了不同的to屬性 -->
      <router-link to="/user/123">User123</router-link>
      <router-link to="/user/456">User456</router-link>
    </header>
    <router-view></router-view>   
  </div>
</template>

router.js 配置user動態路由

const routes = [
    {
        path:"/home",
        component: home
    },
    {
        path: "/about",
        component: about
    },
    /*新增user路徑,配置了動態的id*/
    {
        path: "/user/:id",
        component: user
    },
    {
        path: '/', 
        redirect: '/home' 
    }
]

這時在頁面中點選user123 和user456, 可以看到它們都導航到user元件,配置正確。

在動態路由中,怎麼獲取到動態部分? 因為在元件中是可以顯示不同部分的,就是上面提到的“你的名字”。其實,當整個vue-router 注入到根例項後,在元件的內部,可以通過this.$route 來獲取到 router 例項。它有一個params 屬性,就是來獲得這個動態部分的。它是一個物件,屬性名,就是路徑中定義的動態部分 id, 屬性值就是router-link中to 屬性中的動態部分,如123。使用vuex時,元件中想要獲取到state 中的狀態,是用computed 屬性,在這裡也是一樣,在元件中,定義一個computed 屬性dynamicSegment, user 元件修改如下:

<template>
    <div>
        <h1>User</h1>
        <div>我是user元件, 動態部分是{{dynamicSegment}}</div>
    </div>
</template>
<script>
    export default {
        computed: {
            dynamicSegment () {
                return this.$route.params.id
            }
        }
    }
</script>

這個:後面的程式碼是this.$route.params.id

這裡還有最後一個問題,就是動態路由在來回切換時,由於它們都是指向同一組件,vue不會銷燬再建立這個元件,而是複用這個元件,就是當第一次點選(如:user123)的時候,vue 把對應的元件渲染出來,但在user123, user456點選來回切換的時候,這個元件就不會發生變化了,元件的生命週期不管用了。這時如果想要在元件來回切換的時候做點事情,那麼只能在元件內部(user.vue中)利用watch 來監聽 r o u t e route 的變化。把上面的程式碼用監聽 route 實現

<script>
    export default {
        data () {
            return {
                dynamicSegment: ''
            }
        },
        watch: {
            $route (to,from){
                // to表示的是你要去的那個元件,from 表示的是你從哪個元件過來的,它們是兩個物件,你可以把它打印出來,它們也有一個param 屬性
                console.log(to);
                console.log(from);
                this.dynamicSegment = to.params.id
            }
        }
    }
</script>

巢狀路由
 巢狀路由,主要是由我們的頁面結構所決定的。當我們進入到home頁面的時候,它下面還有分類,如手機系列,平板系列,電腦系列。當我們點選各個分類的時候,它還是需要路由到各個部分,如點選手機,它肯定到對應到手機的部分。

在路由的設計上,首先進入到 home ,然後才能進入到phone, tablet, computer. Phone, tablet, compute 就相當於進入到了home的子元素。所以vue 提供了childrens 屬性,它也是一組路由,相當於我們所寫的routes。
   首先,在home頁面上定義三個router-link 標籤用於導航,然後再定義一個router-view標籤,用於渲染對應的元件。router-link 和router-view 標籤要一一對應。home.vue 元件修改如下:

<template>
    <div>
        <h1>home</h1>
<!-- router-link 的to屬性要注意,路由是先進入到home,然後才進入相應的子路由如 phone,所以書寫時要把 home 帶上 -->
        <p>
            <router-link to="/home/phone">手機</router-link>
            <router-link to="/home/tablet">平板</router-link>
            <router-link to="/home/computer">電腦</router-link>
        </p>
        <router-view></router-view>
    </div>
</template>
const routes = [
    {
        path:"/home",
     // 下面這個屬性也不少,因為,我們是先進入home頁面,才能進入子路由
        component: home,
     // 子路由
        children: [
            {
                path: "phone",
                component: phone
            },
            {
                path: "tablet",
                component: tablet
            },
            {
                path: "computer",
                component: computer
            }
        ]
    },
    {
        path: "/about",
        component: about
    },
    {
        path: "/user/:id",
        component: user
    },
    {
        path: '/', 
        redirect: '/home' 
    }
]

命名路由
 命名路由,很簡單,因為根據名字就可以知道,這個路由有一個名字,那就直接給這個路由加一個name 屬性,就可以了。 給user 路由加一個name 屬性:

{
        path: "/user/:id",
        name: "user",
        component: user
}

命名路由的使用, 在router-link 中to 屬性就可以使用物件了,

 <router-link to="/user/123">User123</router-link> // 和下面等價 
 <router-link :to="{ name: 'user', params: { userId: 123 }}">User</router-link>   // 當使用物件作為路由的時候,to前面要加一個冒號,表示繫結

程式設計式導航:這主要應用到按鈕點選上。當點選按鈕的時候,跳轉另一個元件, 這隻能用程式碼,呼叫rourter.push() 方法。 當們把router 注入到根例項中後,元件中通過 this.$router 可以獲取到router, 所以在元件中使用

this.$router.push(“home”), 就可以跳轉到home介面