從頭開始學習vue-router

浪裡行舟發表於2019-03-04

一、前言

要學習vue-router就要先知道這裡的路由是什麼?為什麼我們不能像原來一樣直接用標籤編寫連結哪?vue-router如何使用?常見路由操作有哪些?等等這些問題,就是本篇要探討的主要問題。

二、vue-router是什麼

這裡的路由並不是指我們平時所說的硬體路由器,這裡的路由就是SPA(單頁應用)的路徑管理器。再通俗的說,vue-router就是WebApp的連結路徑管理系統。
vue-router是Vue.js官方的路由外掛,它和vue.js是深度整合的,適合用於構建單頁面應用。vue的單頁面應用是基於路由和元件的,路由用於設定訪問路徑,並將路徑和元件對映起來。傳統的頁面應用,是用一些超連結來實現頁面切換和跳轉的。在vue-router單頁面應用中,則是路徑之間的切換,也就是元件的切換。路由模組的本質 就是建立起url和頁面之間的對映關係

至於我們為啥不能用a標籤,這是因為用Vue做的都是單頁應用(當你的專案準備打包時,執行npm run build時,就會生成dist資料夾,這裡面只有靜態資源和一個index.html頁面),所以你寫的標籤是不起作用的,你必須使用vue-router來進行管理。

三、vue-router實現原理

SPA(single page application):單一頁面應用程式,只有一個完整的頁面;它在載入頁面時,不會載入整個頁面,而是隻更新某個指定的容器中內容。單頁面應用(SPA)的核心之一是: 更新檢視而不重新請求頁面;vue-router在實現單頁面前端路由時,提供了兩種方式:Hash模式和History模式;根據mode引數來決定採用哪一種方式。

1、Hash模式:

vue-router 預設 hash 模式 —— 使用 URL 的 hash 來模擬一個完整的 URL,於是當 URL 改變時,頁面不會重新載入。 hash(#)是URL 的錨點,代表的是網頁中的一個位置,單單改變#後的部分,瀏覽器只會滾動到相應位置,不會重新載入網頁,也就是說hash 出現在 URL 中,但不會被包含在 http 請求中,對後端完全沒有影響,因此改變 hash 不會重新載入頁面;同時每一次改變#後的部分,都會在瀏覽器的訪問歷史中增加一個記錄,使用”後退”按鈕,就可以回到上一個位置;所以說Hash模式通過錨點值的改變,根據不同的值,渲染指定DOM位置的不同資料。hash 模式的原理是 onhashchange 事件(監測hash值變化),可以在 window 物件上監聽這個事件

2、History模式:

由於hash模式會在url中自帶#,如果不想要很醜的 hash,我們可以用路由的 history 模式,只需要在配置路由規則時,加入”mode: `history`”,這種模式充分利用了html5 history interface 中新增的 pushState() 和 replaceState() 方法。這兩個方法應用於瀏覽器記錄棧,在當前已有的 back、forward、go 基礎之上,它們提供了對歷史記錄修改的功能。只是當它們執行修改時,雖然改變了當前的 URL ,但瀏覽器不會立即向後端傳送請求

//main.js檔案中
const router = new VueRouter({
  mode: `history`,
  routes: [...]
})
複製程式碼

當你使用 history 模式時,URL 就像正常的 url,例如 yoursite.com/user/id,比較好…
不過這種模式要玩好,還需要後臺配置支援。因為我們的應用是個單頁客戶端應用,如果後臺沒有正確的配置,當使用者在瀏覽器直接訪問 oursite.com/user/id 就會返回 404,這就不好看了。
所以呢,你要在服務端增加一個覆蓋所有情況的候選資源:如果 URL 匹配不到任何靜態資源,則應該返回同一個 index.html 頁面,這個頁面就是你 app 依賴的頁面。

 export const routes = [ 
  {path: "/", name: "homeLink", component:Home}
  {path: "/register", name: "registerLink", component: Register},
  {path: "/login", name: "loginLink", component: Login},
  {path: "*", redirect: "/"}]
複製程式碼

此處就設定如果URL輸入錯誤或者是URL 匹配不到任何靜態資源,就自動跳到到Home頁面

3、使用路由模組來實現頁面跳轉的方式

方式1:直接修改位址列

方式2:this.$router.push(‘路由地址’)

方式3:<router-link to="路由地址"></router-link>

四、vue-router使用方式

  1:下載 npm i vue-router -S
  2:在main.js中引入 import VueRouter from `vue-router`;
  3:安裝外掛 Vue.use(VueRouter);
  4:建立路由物件並配置路由規則 let router = new VueRouter({routes:[{path:`/home`,component:Home}]});
  5:將其路由物件傳遞給Vue的例項,options中加入 router:router
  6:在app.vue中留坑 <router-view></router-view>
複製程式碼

具體實現請看如下程式碼:

//main.js檔案中引入
import Vue from `vue`;
import VueRouter from `vue-router`;
//主體
import App from `./components/app.vue`;
import Home from `./components/home.vue`
//安裝外掛
Vue.use(VueRouter); //掛載屬性
//建立路由物件並配置路由規則
let router = new VueRouter({
    routes: [
        //一個個物件
        { path: `/home`, component: Home }
    ]
});
//new Vue 啟動
new Vue({
    el: `#app`,
    //讓vue知道我們的路由規則
    router: router, //可以簡寫router
    render: c => c(App),
})
複製程式碼

最後記得在在app.vue中“留坑”

//app.vue中
<template>
    <div>
        <!-- 留坑,非常重要 -->
        <router-view></router-view>
    </div>
</template>
<script>
    export default {
        data(){
            return {}
        }
    }
</script>
複製程式碼

五、vue-router核心要點

1.vue-router引數傳遞

宣告式的導航<router-link :to="...">和程式設計式的導航router.push(...)都可以傳參,本文主要介紹前者的傳參方法,同樣的規則也適用於程式設計式的導航。

①用name傳遞引數

在路由檔案src/router/index.js裡配置name屬性

routes: [
    {
      path: `/`,
      name: `Hello`,
      component: Hello
    }
]
複製程式碼

模板裡(src/App.vue)用$route.name來接收
比如:<p>{{ $route.name}}</p>

②通過<router-link> 標籤中的to傳參

這種傳參方法的基本語法:

<router-link :to="{name:xxx,params:{key:value}}">valueString</router-link>

比如先在src/App.vue檔案中

<router-link :to="{name:`hi1`,params:{username:`jspang`,id:`555`}}">Hi頁面1</router-link>

然後把src/router/index.js檔案裡給hi1配置的路由起個name,就叫hi1.

{path:`/hi1`,name:`hi1`,component:Hi1}

最後在模板裡(src/components/Hi1.vue)用$route.params.username進行接收.

{{$route.params.username}}-{{$route.params.id}}

③vue-router 利用url傳遞引數—-在配置檔案裡以冒號的形式設定引數。

我們在/src/router/index.js檔案裡配置路由

{
    path:`/params/:newsId/:newsTitle`,
    component:Params
}
複製程式碼

我們需要傳遞引數是新聞ID(newsId)和新聞標題(newsTitle).所以我們在路由配置檔案裡制定了這兩個值。
在src/components目錄下建立我們params.vue元件,也可以說是頁面。我們在頁面裡輸出了url傳遞的的新聞ID和新聞標題。

<template>
    <div>
        <h2>{{ msg }}</h2>
        <p>新聞ID:{{ $route.params.newsId}}</p>
        <p>新聞標題:{{ $route.params.newsTitle}}</p>
    </div>
</template>
<script>
export default {
  name: `params`,
  data () {
    return {
      msg: `params page`
    }
  }
}
</script>
複製程式碼

在App.vue檔案里加入我們的<router-view>標籤。這時候我們可以直接利用url傳值了

<router-link to="/params/198/jspang website is very good">params</router-link>

④使用path來匹配路由,然後通過query來傳遞引數

<router-link :to="{ name:`Query`,query: { queryId:  status }}" >
     router-link跳轉Query
</router-link>

複製程式碼

對應路由配置:

   {
     path: `/query`,
     name: `Query`,
     component: Query
   }
複製程式碼

於是我們可以獲取引數:

this.$route.query.queryId
複製程式碼

2.單頁面多路由區域操作

在一個頁面裡我們有2個以上<router-view>區域,我們通過配置路由的js檔案,來操作這些區域的內容

①App.vue檔案,在<router-view>下面新寫了兩行<router-view>標籤,並加入了些CSS樣式

<template>
  <div id="app">
    <img src="./assets/logo.png">
       <router-link :to="{name:`HelloWorld`}"><h1>H1</h1></router-link>
       <router-link :to="{name:`H1`}"><h1>H2</h1></router-link>
    <router-view></router-view>
    <router-view name="left" style="float:left;width:50%;background-color:#ccc;height:300px;"/>
    <router-view name="right" style="float:right;width:50%;background-color:yellowgreen;height:300px;"/>
  </div>
</template>
複製程式碼

②需要在路由裡配置這三個區域,配置主要是在components欄位裡進行

export default new Router({
    routes: [
      {
        path: `/`,
        name: `HelloWorld`,
        components: {default: HelloWorld,
          left:H1,//顯示H1元件內容`I am H1 page,Welcome to H1`
          right:H2//顯示H2元件內容`I am H2 page,Welcome to H2`
        }
      },
      {
        path: `/h1`,
        name: `H1`,
        components: {default: HelloWorld,
          left:H2,//顯示H2元件內容
          right:H1//顯示H1元件內容
        }
      }
    ]
  })
複製程式碼

上邊的程式碼我們編寫了兩個路徑,一個是預設的‘/’,另一個是‘/Hi’.在兩個路徑下的components裡面,我們對三個區域都定義了顯示內容。最後頁面展示如下圖:

從頭開始學習vue-router

3.vue-router配置子路由(二級路由)

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

從頭開始學習vue-router

如何實現下圖效果(H1頁面和H2頁面巢狀在主頁中)

從頭開始學習vue-router

①首先用標籤增加了兩個新的導航連結

<router-link :to="{name:`HelloWorld`}">主頁</router-link>
<router-link :to="{name:`H1`}">H1頁面</router-link>
<router-link :to="{name:`H2`}">H2頁面</router-link>
複製程式碼

②在HelloWorld.vue加入<router-view>標籤,給子模板提供插入位置

<template>
 <div class="hello">
   <h1>{{ msg }}</h1>
   <router-view></router-view>
 </div>
</template>
複製程式碼

③在components目錄下新建兩個元件模板 H1.vue 和 H2.vue
兩者內容類似,以下是H1.vue頁面內容:

<template>
 <div class="hello">
   <h1>{{ msg }}</h1>
 </div>
</template>
<script>
 export default {
   data() {
     return {
       msg: `I am H1 page,Welcome to H1`
     }
   }
 }
![clipboard.png](/img/bVbiDh9)

</script>
複製程式碼

④修改router/index.js程式碼,子路由的寫法是在原有的路由配置下加入children欄位。

  routes: [
   {
     path: `/`,
     name: `HelloWorld`,
     component: HelloWorld,
     children: [{path: `/h1`, name: `H1`, component: H1},//子路由的<router-view>必須在HelloWorld.vue中出現
       {path: `/h2`, name: `H2`, component: H2}
     ]
   }
 ]
複製程式碼

4.$route$router 的區別

我們先將這兩者console.log列印出來:

從頭開始學習vue-router
從頭開始學習vue-router
  • $route 是“路由資訊物件”,包括 path,params,hash,query,fullPath,matched,name 等路由資訊引數。

$route.path
字串,對應當前路由的路徑,總是解析為絕對路徑,如 “/order”。

$route.params
一個 key/value 物件,包含了 動態片段 和 全匹配片段,
如果沒有路由引數,就是一個空物件。

$route.query
一個 key/value 物件,表示 URL 查詢引數。
例如,對於路徑 /foo?user=1,則有 $route.query.user為1,
如果沒有查詢引數,則是個空物件。

$route.hash
當前路由的 hash 值 (不帶 #) ,如果沒有 hash 值,則為空字串。

$route.fullPath
完成解析後的 URL,包含查詢引數和 hash 的完整路徑。

$route.matched
陣列,包含當前匹配的路徑中所包含的所有片段所對應的配置引數物件。

$route.name 當前路徑名字

  • $router 是“路由例項”物件,即使用 new VueRouter建立的例項,包括了路由的跳轉方法,鉤子函式等。

$router常見跳轉方法

<button @click="goToMenu" class="btn btn-success">Let`s order!</button>
.....
<script>
  export default{
    methods:{
      goToMenu(){
        this.$router.go(-1)//跳轉到上一次瀏覽的頁面
        this.$router.replace(`/menu`)//指定跳轉的地址
        this.$router.replace({name:`menuLink`})//指定跳轉路由的名字下
        this.$router.push(`/menu`)//通過push進行跳轉
        this.$router.push({name:`menuLink`})//通過push進行跳轉路由的名字下
      }
    }
  }
</script>
複製程式碼

$router.push$router.replace的區別

  • 使用push方法的跳轉會向 history 棧新增一個新的記錄,當我們點選瀏覽器的返回按鈕時可以看到之前的頁面。
  • 使用replace方法不會向 history 新增新記錄,而是替換掉當前的 history 記錄,即當replace跳轉到的網頁後,‘後退’按鈕不能檢視之前的頁面。

5.404頁面的設定

使用者會經常輸錯頁面,當使用者輸錯頁面時,我們希望給他一個友好的提示頁面,這個頁面就是我們常說的404頁面。vue-router也為我們提供了這樣的機制。
①設定我們的路由配置檔案(/src/router/index.js)

{
   path:`*`,
   component:Error
}
複製程式碼

這裡的path:`*`就是輸入地址不匹配時,自動顯示出Error.vue的檔案內容

②在/src/components/資料夾下新建一個Error.vue的檔案。簡單輸入一些有關錯誤頁面的內容。

<template>
    <div>
        <h2>{{ msg }}</h2>
    </div>
</template>
<script>
export default {
  data () {
    return {
      msg: `Error:404`
    }
  }
}
</script>
複製程式碼

此時我們隨意輸入一個錯誤的地址時,便會自動跳轉到404頁面

六、參考文章

vue-router實現單頁面路由原理

Vue.js——vue-router 60分鐘快速入門

技術胖的Vue-router視訊教程

vue中$router以及$route的使用

Vue2.0 探索之路——vue-router入門教程和總結

vue-router 2.0一些區別

相關文章