可能比文檔還詳細--VueRouter徹底指北

前言

關於標題,應該算不上是標題黨,由於內容真的不少很長很全面.主要是在官網的基礎上又詳細總結,舉例了不少東西.確保全部新人都能理解!因此實際上不少東西是比官網還詳細的.你想要的,在官網上沒理解的,基本在這裏都能找到解答!原本想分紅兩篇發的,但想一想男人長點也沒什麼很差的.因此也但願各位收藏插眼標記(滑稽)html

特色:本文主要是參考了官方文檔.除了不經常使用的過渡動效和數據獲取,都進行了分析說明.說明:每一節都在文檔的基礎上進行了更通俗的解釋;例子:每一節都添加了單獨的例子進行詳細的說明,官方沒有或複雜或略過的都有詳細的說明.總結:每一節都會有tips注意點,實際開發的經驗和總結.前端

使用方法:vue

若是是新手,就從頭開始看,前5章的內容都是逐步讓你熟悉VueRouter,而且第5章也給出了本地實際搭建的代碼示例.react

若是你對VueRouter有了必定了解,則能夠根據目錄,自行選擇查看.或者全局搜索關鍵字快速定位.webpack

吐槽:如今關於VueRouter相關能搜到的大部分都是copy徹底摘抄官方文檔拼湊的文章.很反感這樣的文章!基本沒什麼養分!你在官網上不明白的在他那裏基本也看不明白.web

1, 概述

vue-router和vue.js是深度集成的,適合用於單頁面應用.傳統的路由是用一些超連接來實現頁面切換和跳轉.而vue-router在單頁面應用中,則是組件之間的切換.其本質就是:創建並管理url和對應組件之間的映射關係.vue-router

2, 簡單實例

這裏簡單先以官網的例子,瞭解vue-router有哪幾大部分組成,對vue-router有一個初步印象.npm

HTML

首先是html部分.這裏主要是兩個做用:編程

1,router-link組件來導航,用戶點擊後切換到相關視圖.segmentfault

2,router-view組件來設置切換的視圖在哪裏渲染.(一個頁面也能夠有多個router-view分別展現特定的視圖,而且支持嵌套)

<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>

<div id="app">
  <h1>Hello App!</h1>
  <p>
    <!-- 使用 router-link 組件來導航. -->
    <!-- 經過傳入 `to` 屬性指定連接. -->
    <!-- <router-link> 默認會被渲染成一個 `<a>` 標籤 -->
    <router-link to="/foo">Go to Foo</router-link>
    <router-link to="/bar">Go to Bar</router-link>
  </p>
  <!-- 路由出口 -->
  <!-- 路由匹配到的組件將渲染在這裏 -->
  <router-view></router-view>
</div>

複製代碼

JavaScript

這裏實際項目寫法代碼能夠參考我後面的第5章.下面我就簡單總結下大概分那幾步:

  • 1,材料準備:
    • 1.1 引入準備好的'Vue'和'vue-router'(前提是已經npm)
    • 1.2 引入路由跳轉的組件.下面例子中就是'Foo'和'Bar'
    • 1.3 啓動全局組件VueRouter例如:Vue.use(VueRouter).這樣vue-router纔開始執行.
  • 2, 配置路由實例:經過new VueRouter()詳細配置每一個路由的路徑,對應的組件等等全部和路由相關的配置.
  • 3, 將路由實例掛載到根實例上.new Vue({router}).$mount('#app')
// 0\. 若是使用模塊化機制編程,導入Vue和VueRouter,要調用 Vue.use(VueRouter)

// 1\. 定義 (路由) 組件。
// 能夠從其餘文件 import 進來
const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }

// 2\. 定義路由
// 每一個路由應該映射一個組件。 其中"component" 能夠是
// 經過 Vue.extend() 建立的組件構造器,
// 或者,只是一個組件配置對象。
// 咱們晚點再討論嵌套路由。
const routes = [
  { path: '/foo', component: Foo },
  { path: '/bar', component: Bar }
]

// 3\. 建立 router 實例,而後傳 `routes` 配置
// 你還能夠傳別的配置參數, 不過先這麼簡單着吧。
const router = new VueRouter({
  routes // (縮寫) 至關於 routes: routes
})

// 4\. 建立和掛載根實例。
// 記得要經過 router 配置參數注入路由,
// 從而讓整個應用都有路由功能
const app = new Vue({
  router
}).$mount('#app')

// 如今,應用已經啓動了!

複製代碼

經過注入路由器,咱們能夠在任何組件內經過 this.$router 訪問路由器,也能夠經過 this.$route訪問當前路由對象:

Tips:這裏我簡單說明下$router$route的區別:

  • $router是指整個路由實例,你能夠操控整個路由,經過'$router.push'往其中添加任意的路由對象.
  • $route:是指當前路由實例('$router')跳轉到的路由對象;
  • 路由實例能夠包含多個路由對象.它們是父子包含關係.
// Home.vue
export default {
  computed: {
    username () {
      // 咱們很快就會看到 `params` 是什麼
      return this.$route.params.username
    }
  },
  methods: {
    goBack () {
      window.history.length > 1
        ? this.$router.go(-1)
        : this.$router.push('/')
    }
  }
}
複製代碼

3, vue-router簡略圖示關係(有問題須要修改)

圖片中router.js就是路由實例配置文件

vue-router簡略圖示關係
PS: 這裏圖說的有點不許確,to並非僅僅對應path值.要分具體狀況, 詳情查看官方to的api.

4, 學習的準備工做 !important

4.1 硬件準備

學習一個新知識,只看而後想一想.嗯,大概是這樣的.這樣是沒有任何效果的.沒有實際敲過,使用過,都算不上是你的知識.因此,強烈建議你們邊看邊敲邊思考總結. 這裏提供兩種方式:

  • 官網在線實例:點擊這裏經過在線實例,按照教程邊看邊敲!
  • 經過我第5章的教程,在本身本地的實際項目上進行構建,查看效果.

這兩種方式都很好.我的建議有條件的選第二種,更加直觀,更加貼近本身的實際項目需求.

4.2 思想準備

學習配置vue-router,必定要考慮兩個層面:

  • Html:對應的就是vue-router裏的<router-link><router-view>
  • JavaScript:就是具體路由實例的配置. 整個vue-router的配置也是圍繞這兩個層面進行展開的,學習時必定要有這個意識,才更容易理解和使用!

5, 實際項目構建示例

5.1,下載vue-router :

npm i vue-router -s
複製代碼

5.2, 在vue組件內配置router-link和router-view

  • router-link:映射路由.就是建立a標籤來定義路由導航的連接(用戶經過點擊實現跳轉).經過to屬性指定目標地址.默認渲染成帶有正確連接的<a>標籤.
  • router-view:就是在標籤內渲染你路由匹配到的視圖組件.router-view支持嵌套router-view,而且支持多個router-view分別渲染不一樣的component.詳細點擊文檔命名視圖.
<!--這裏引用官方例子的寫法-->
<div id='app'>
	<p>
		<router-link to="/user/foo">/user/foo</router-link>
		<router-link to="/user/bar">/user/bar</router-link>
	</p>
	<router-view>PS:寫在這裏,即router-view裏的內容是不會顯示在頁面上的!</router-view>
</div>
複製代碼

關於to的更詳細用法: 能夠參考官方的api文檔.用法很簡單這裏我就不重複了.

5.3, 配置路由實例 router.js文件

//第一步:引入必要的文件
import Vue from 'vue';//加載全局組件時,都須要引入Vue
import Router from 'vue-router';//引入vue-router
//引入在路由中須要用到的組件
import User from '@/components/user/User' //這裏省略了.vue
...

//第二步:加載Router
Vue.use(Router);//加載全局組件Router

//第三步:配置路由實例
export default new Router({
	//mode:'history', //路由模式:默認爲hash,若是改成history,則須要後端進行配合
	//base:'/',//基路徑:默認值爲'/'.若是整個單頁應用在/app/下,base就應該設爲'/app/'.通常能夠寫成__dirname,在webpack中配置.
	routes:[{
		path: '/user', 
		name: 'user', //給路由命名,設置的name要惟一!
		component: User//就是第一步import的組件
		},{
			//路由懶加載:單頁面應用,首頁時,加載內容時間過長.運用懶加載對頁面組件進行劃分,減小首頁加載時間
			path:'/Page',
			name:'Page',
			component:resolve => require(['@/components/Page'],resolve)
			//此時component則不須要在第一步import
		}]
})
複製代碼

5.4, 在main.js中引入router.js並掛載到Vue實例

建議在實際項目中將router配置單獨的js文件,更加清晰,不要都混在main.js中.

import router from './router'

new Vue({
  el: '#app',
  router,//不簡寫就是router:router,
  store,
  template: '<App/>',
  components: {
  App

  } })
複製代碼

5.5, router,routes,route傻傻分不清?

  • 1, router:通常指的就是路由實例.如$router.
  • 2, routes:指router路由實例的routes API.用來配置多個route路由對象.
  • 3, route:指的就是路由對象.例如;$route指的就是當前路由對象.

5.6, 小結

至此,一個基本的vue-router已經完成.這裏只是簡單示範,瞭解其實現步驟. 總結一下編寫vue路由時,記住要作這三類事: 1,準備工做: 在main.js中引入router.js掛載到Vue實例中. 2,配置路由實例(重點): 在router.js中引入Vue,vue-router,配置路由實例. 3,組件內配置: 就是配置router-link和router-view.

6, vue-router的兩種模式

通常單頁面應用是(SPA)不會請求頁面而是隻更新視圖. vue-router提供了兩種方式來實現前端路由:Hash模式和History模式,能夠用mode參數來決定使用哪種方式.

6.1,Hash模式

vue-router默認使用Hash模式.使用url的hash來模擬一個完整的url.此時url變化時,瀏覽器是不會從新加載的.Hash(即#)是url的錨點,表明的是網頁中的一個位置,僅僅改變#後面部分,瀏覽器只會滾動對應的位置,而不會從新加載頁面.#僅僅只是對瀏覽器進行指導,而對服務端是徹底沒有做用的!它不會被包括在http請求中,故也不會從新加載頁面.同時hash發生變化時,url都會被瀏覽器記錄下來,這樣你就可使用瀏覽器的後退了.

總而言之:Hash模式就是經過改變#後面的值,實現瀏覽器渲染指定的組件.

6.2,History模式

若是你不喜歡hash這種#樣式.可使用history模式.這種模式利用了HTML5 History新增的pushState()和replaceState()方法. 除了以前的back,forward,go方法,這兩個新方法能夠應用在瀏覽器歷史記錄的增長替換功能上.使用History模式,經過歷史記錄修改url,但它不會當即向後端發送請求. 注意點: 雖然History模式能夠丟掉不美觀的#,也能夠正常的前進後退,可是刷新f5後,此時瀏覽器就會訪問服務器,在沒有後臺支持的狀況下,此時就會獲得一個404!官方文檔給出的描述是:"不過這種模式要玩好,還須要後臺配置支持.由於咱們的應用是單個客戶端應用,若是後臺沒有正確的配置,當用戶直接訪問時,就會返回404.因此呢,你要在服務端增長一個覆蓋全部狀況的的候選資源;若是url匹配不到任何靜態資源,則應該返回同一個index.html頁面."

總而言之:History模式就是經過pushState()方法來對瀏覽器的瀏覽記錄進行修改,來達到不用請求後端來渲染的效果.不過建議,實際項目仍是使用history模式.

例子:

const router = new VueRouter({
  mode: 'history', //若是這裏不寫,路由默認爲hash模式
  routes: [...]
})
複製代碼

7,動態路由匹配

當咱們常常須要把某種模式匹配到全部的路由,所有都映射到同個組件.例如:咱們有一個User組件,對於全部ID各不相同的用戶,都要使用這個組件來渲染.這時咱們就能夠配置動態路由來實現. 動態路由匹配本質上就是經過url進行傳參

7.1,路由對象屬性介紹:

爲了下面理解的方便這裏簡單介紹下經常使用的路由對象屬性,在組件內能夠經過this.$route(不是$router!)進行訪問.

$route.path 類型: string 字符串,對應當前路由的路徑,老是解析爲絕對路徑,如 "/foo/bar"

$route.params 類型: Object 一個 key/value 對象,包含了動態片斷和全匹配片斷,若是沒有路由參數,就是一個空對象。

$route.query 類型: Object 一個 key/value 對象,表示 URL 查詢參數。例如,對於路徑 /foo?user=1,則有 $route.query.user == 1,若是沒有查詢參數,則是個空對象。

$route .name 當前路由的名稱,若是有的話。這裏建議最好給每一個路由對象命名,方便之後編程式導航.不過記住name必須惟一!

$route.hash 類型: string 當前路由的 hash 值 (帶 #) ,若是沒有 hash 值,則爲空字符串。

$route.fullPath 類型: string 完成解析後的 URL,包含查詢參數和 hash 的完整路徑。

$route.matched 類型: Array<RouteRecord> 一個數組,包含當前路由的全部嵌套路徑片斷的路由記錄 。路由記錄就是 routes 配置數組中的對象副本 (還有在 children 數組)。 $route.redirectedFrom 若是存在重定向,即爲重定向來源的路由的名字。

7.2 使用params進行配置:

舉個例子:

routes:[{
	//動態路徑參數,以冒號開頭
	path:'/user/:id',
	component:User
}]
複製代碼

這樣,就是使用params進行配置.像/user/foo和/user/bar都將映射到相同的路由.

  • 一個路徑參數使用':'冒號進行標記.
  • 當匹配到一個路由時,參數就會被設置到this.$route.params,能夠在每一個組件內使用.例如/user/foo在this.$route.params.id就爲foo

這裏以官方的表格示例進行展現

模式 匹配路徑 $route.params
/user/:username /user/evan { username: 'evan' }
/user/:username/post/:post_id /user/evan/post/123 { username: 'evan', post_id: 123 }

這裏再舉一個稍微變化一下的例子,來加深理解:

routes:[
	{path:'/user/:shot/foo/:id', component:shotCat}
]
複製代碼
<p>
	<router-link to="/user/shot/foo">/user/shot/foo</router-link>  	<!--沒法匹配到對應路由-->	
	<router-link to="/user/shot/cat/foo">/user/shot/cat/foo</router-link>	<!--沒法匹配到對應路由-->	
	<router-link to="/user/foo/foo/foo">/user/foo/foo/foo</router-link>	<!--成功匹配,$route.params.shot爲foo;$route.params.cat爲foo;-->	
	<router-link to="/user/shot/foo/cat">/user/shot/foo/cat</router-link><!--成功匹配,$route.params.shot爲shot;$route.params.cat爲cat;-->	
</p>
<router-view></router-view>
複製代碼

tips:

  • 有時候,同一個路徑能夠匹配多個路由,此時,匹配的優先級就按照路由的定義順序.誰先定義的,誰的優先級就最高.
  • 因爲路由參數對組件實例是複用的.例如:/user/foo 和 /user/bar在使用路由參數時,複用的都是User組件.此時組件的生命週期鉤子不會再被調用。若是你想路徑切換時,進行一些初始化操做時,能夠用如下兩種解決辦法:
    • 在組件內 watch $route 對象:
    const User = {
     template: '...',
     watch: {
       '$route' (to, from) {
         // 對路由變化做出響應...
       }
     }
    }
    複製代碼
    • 使用2.2版本中的 beforeRouteUpdate 路由守衛:
    const User = {
      template: '...',
      beforeRouteUpdate (to, from, next) {
    	// react to route changes...
    	// don't forget to call next()
      }
    }
    複製代碼

7.3,經過query進行配置傳參.

在項目裏咱們能夠經過上面提到的params進行傳參.同時也能夠用query進行傳參. 舉個例子: <router-link to="/user?id=foo">foo</router-link> vue-route會自動將?後的id=foo封裝進this.$route.query裏. 此時,在組件裏this.$route.query.id值爲'foo'. ==除了經過router-linkto屬性. query也能夠經過後面講到的編程式導航進行傳參==

8, 編程式導航

什麼是編程式導航,編程式導航就是在vue組件內部經過this.$router訪問路由實例,並經過this.$router.push導航到不一樣的url,進行路由映射,因此 它的做用是和<router-link :to>是一毛同樣的! 固然,前提是你已經在routes裏配置了對應的路由對象.

通常何時用到編程式導航? 若是,你想在路由跳轉前作點其餘事情,例如權限驗證等.可是用<router-link>的話,就直接跳轉了.此時就可使用編程式導航!

8.1, 編程式導航的寫法

編程式導航通常都是用到router.push方法.該方法的參數能夠是一個字符串路徑,或者一個描述地址的對象.例如:

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

//對象
this.$ruter.push({path:'home'})

//命名路由
this.$router.push({name:'user',params:{userId:2333}})

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

複製代碼

注意:==原諒色警告==:pathparams是不能同時生效的!,不然params會被忽略掉.因此使用對象寫法進行params傳參時,要麼就是path加冒號:,要麼就是像上例中的'命名路由'.經過name和params進行傳參.然而query卻並不受影響,有沒有path均可以進行傳參.

8.2, router.replace方法

router.replace和router.push很像,寫法同樣.但實際效果不同.push是向history裏添加新記錄.而replace是直接將當前瀏覽器history記錄替換掉!

那最直接的後果是什麼呢? 舉個例子:

  • 用push方法,頁面1跳轉到頁面2,你使用瀏覽器的後退能夠回到頁面1
  • 用replace方法,頁面1被替換成頁面2,你使用瀏覽器的後退,此時你回不到頁面1,只能回到頁面1的前一頁,頁面0.

那何時會用到replace呢? 當你不想讓用戶回退到以前的頁面時,常見於權限驗證,驗證後就不讓用戶回退到登陸頁重複驗證.

8.3, router.go(n)方法

這個方法的參數就是一個整數,意思是在history記錄中前進或後退多少步.相似window.history.go(n).這樣就能控制頁面前進或者後退多少步.

9 對動態路由和編程式導航相關的補充小結:

補充: 實際上不經過routes配置,也能夠用下面這種方法直接在router-link上經過to進行傳參. 關於to的更詳細用法: 能夠參考官方的api文檔.用法很簡單這裏我就不重複了.

routes:[
	{name:'shotCat',path:'/shotCat', component:shotCat}
]
複製代碼
<router-link :to="{ name:'shotCat',params:{paramId:'hello'},query:{queryId:'world'}}">helloWorld</router-link> <!--此時經過name匹配到路由對象shotCat.-->	 
<router-link :to="{ path:'/shotCat',params:{paramId:'hello'},query:{queryId:'world'}}">helloWorld</router-link>  <!--此時經過path匹配到路由對象shotCat.可是!!!!!此時`paramId`並不能添加到`$route.params`裏,只有`queryId`成功添加到`$route.query`-->
複製代碼

經過兩個router-link.能夠發現這種寫法和編程式導航的規則一毛同樣, pathparams是不能同時生效的! 因此建議你們最好給每一個路由對象進行命名!** query是path和name均可以正常傳參的. 這裏你們能夠經過這個官方在線例子進行修改驗證{{$route.params}}{{$route.query}}是否成功傳遞. 小結:

  • 1,<router-link :to="{ }">等同於this.$router.psh(). pathparams是不能同時存在的!,想經過params,就得加上name屬性.query不受影響.
  • 2,<router-link :to="{ }">this.$router.psh()的實際效果也是同樣的.
    • 2.1 params參數都不會顯示在url地址欄中.除了在路由中經過routes進行配置的.因此用戶刷新頁面後,params參數就會丟失!
    • 2.2 query參數能夠正常顯示在url地址欄中.刷新頁面後也不會丟失

經過to雖然能夠進行params,query傳參.可是注意此時頁面url並不會改變!.因此你刷新頁面後,參數就沒有了.

10 嵌套路由與單組件多視圖

  • 嵌套路由:就是父路由嵌套子路由.url上就是/user嵌套兩個子路由後就是/user/foo和/uer/bar.用一張圖表示就是:

嵌套路由

  • 單組件多視圖:就是一個組件裏有多個視圖進行展現.即包含有多個<router-view/>

10.1 嵌套路由

講以前,必須先清楚這樣一件事,一個<router-view/>對應展現的就是一個組件 所以實現嵌套路由有兩個要點:

  • 路由對象中定義子路由(嵌套子路由)
  • 組件內<router-view/>的使用.

這兩點也對應了我第4章中關於思想準備的說明.

下面個人示例仍是以上圖嵌套路由爲例進行講解. 理解了的能夠看官方示例是嵌套路由搭配動態路由使用的例子,你們能夠在此基礎上本身修改嘗試.

10.1.1 路由對象中定義子路由

const router = new VueRouter({
  routes: [
    { path: '/user', component: User,name:'user',
	//嵌套路由就寫在children配置中,寫法和rutes同樣.
      children: [
        { path: '', component: UserDefault ,name:'default',
			//children:[{}] 也能夠繼續添加children嵌套
		},
		//若是/user下沒有匹配到其餘子路由時,User的<router-view>是什麼都不會顯示的,若是你想讓它顯示點什麼.能夠將path:''.設爲空.此時UserDefault就是默認顯示的組件.
		
        { path: 'foo', component: UserFoo,name:'foo'},
		//此時path等同於'/user/foo',子路由會繼承父路由的路徑.可是不能寫成path:'/foo'.由於以 / 開頭的嵌套路徑會被看成根路徑,也就是說此時foo成了根路徑.而不是user.
		
        { path: 'bar', component: UserBar,name:'bar' }
      ]
    }
  ]
})
複製代碼

10.1.2 組件內<router-view/>的使用.

<div id="app">
 <p>
   <router-link to="/user">/user</router-link>
   <router-link to="/user/foo">/user/foo</router-link>
   <router-link to="/user/bar">/user/bar</router-link>
 </p>
 <router-view></router-view> <!--這裏展現的是User組件;一樣User的<router-view/>也被嵌套在裏面-->
</div>
複製代碼
const User = {
 template: ` <div class="user"> <h2>User</h2> <router-view></router-view> </div> `
}
//User的<router-view>裏展現的就是子路由foo,bar的組件還有default默認組件

const UserDefault = { template: '<div>default</div>' }
const UserFoo = { template: '<div>foo</div>' }
const UserBar = { template: '<div>bar</div>' }
複製代碼

10.2 單組件多視圖

若是一個組件有多個視圖,來展現多個子組件.這個時候就須要用到命名視圖 官方的在線示例在這裏,你們能夠在此基礎上本身修改嘗試. 直接上個人例子:

<div id="app">
 <h1>Named Views</h1>
 <p>
   <router-link to="/avenger">復仇者聯盟</router-link>
 </p>
 <router-view ></router-view>
 <router-view name="ironMan"></router-view>
 <router-view name="captainAmerica"></router-view>
</div>
<!--這裏咱們給其中兩個視圖命名爲ironMan和captainAmerica;沒有設置name的視圖,會得到默認命名爲default> 複製代碼
const router = new VueRouter({
  routes: [
    { path: '/avenger', name:'avenger',components: {
        default: stanLee,
        ironMan: ironMan,
        captainAmerica: captainAmerica
      }
	//若是有多個視圖須要展現時,之前的component換成components(加上s!!),寫成對象形式.左邊的ironMan指的就是<router-view>裏設置的name="ironMan";右邊的則指的是下面的組件ironMan.
    }
  ]
})

const stanLee = { template: '<div>斯坦李</div>' }
const ironMan = { template: '<div>鋼鐵俠</div>' }
const captainAmerica = { template: '<div>美國隊長</div>' }
複製代碼

嵌套命名視圖: 官方的在線示例,結合了嵌套路由和命名視圖.就是兩種寫法的組合.建議初學者經過這個例子加深理解.

11 重定向和別名:

11.1 重定向配置:

重定向其實就是經過路由.攔截path,而後替換url跳轉到redirect所指定的路由上. 重定向是經過 routes 配置來完成,

//從 /a 重定向到 /b
const router = new VueRouter({
	routes:[
		{path:'/a',rediret:'/b'}
	]
})

///從 /a 重定向到 命名爲'foo'的路由
const router = new VueRouter({
  routes: [
    { path: '/a', redirect: { name: 'foo' }}
  ]
})

//甚至是一個方法,動態返回重定向目標:
const router = new VueRouter({
  routes: [
    { path: '/a', redirect: to => {
      // 方法接收 目標路由 做爲參數
      // return 重定向的 字符串路徑/路徑對象
	  const { hash, params, query } = to
	  //這裏使用了ES6的解構寫法,分別對應了to的hash模式,params,query參數.這裏解構就不具體說明了.
        if (query.to === 'foo') {
          return { path: '/foo', query: null }
        }
        if (hash === '#baz') {
          return { name: 'baz', hash: '' }
        }
        if (params.id) {
          return '/with-params/:id'
        } else {
          return '/bar'
        }
    }}
  ]
})

複製代碼

11.2 別名

重定向是替url換路徑,達到路由跳轉.那別名就是一個路由有兩個路徑.兩個路徑都能跳轉到該路由. 舉個栗子:你可能大名叫'趙日天',但你的小名(別名)可能就叫'二狗子'.但'趙日天'和'二狗子'指代的是同一我的(路由). 別名是在rutes裏的alias進行配置:

const router = new VueRouter({
//這時,路徑'/fxxksky'和'/two-dogs' 都會跳轉到A
  routes: [
    { path: '/fxxksky', component: A, alias: '/two-dogs' }
	//當有多個別名時,alias也能夠寫成數組形式. alias: ['/two-dogs', 'three-dogs','four-dogs','five-dogs'] 
  ]
})
複製代碼

12 路由組件傳參

路由傳參,能夠經過前面介紹的params和query進行傳參.但這兩種傳參方式,本質上都是把參數放在url上,經過改變url進行的.這樣就會形成參數和組件的高度耦合. 若是我想傳參的時候,能夠更自由,擺脫url的束縛.這時就可使用rute的props進行解耦.提升組件的複用,同時不改變url.

下面就以例子進行講解: PS: 這部分官方沒有在線實例,你們能夠將我下面例子的代碼將以前的在線例子進行覆蓋就能夠了

//路由配置:

const Hello = {
  props: ['name'], //使用rute的props傳參的時候,對應的組件必定要添加props進行接收,不然根本拿不到傳參
  template: '<div>Hello {{ $route.params}}和{{this.name}}</div>'
  //若是this.name有值,那麼name已經成功成爲組件的屬性,傳參成功
}

const router = new VueRouter({
mode: 'history',
  routes: [
    { path: '/', component: Hello }, // 沒有傳參 因此組件什麼都拿不到
    { path: '/hello/:name', component: Hello, props: true }, //布爾模式: props 被設置爲 true,此時route.params (即此處的name)將會被設置爲組件屬性。
    { path: '/static', component: Hello, props: { name: 'world' }}, // 對象模式: 此時就和params沒什麼關係了.此時的name將直接傳給Hello組件.注意:此時的props需爲靜態!
    { path: '/dynamic/:years', component: Hello, props: dynamicPropsFn }, // 函數模式: 1,這個函數能夠默認接受一個參數即當前路由對象.2,這個函數返回的是一個對象.3,在這個函數裏你能夠將靜態值與路由相關值進行處理.
    { path: '/attrs', component: Hello, props: { name: 'attrs' }}
  ]
})

function dynamicPropsFn (route) {
  return {
    name: (new Date().getFullYear() + parseInt(route.params.years)) + '!'
  }
}

new Vue({
  router,
  el: '#app'
})
複製代碼
<!--html部分-->
    <div id="app">
      <h1>Route props</h1>
      <ul>
        <li><router-link to="/">/</router-link></li>
        <li><router-link to="/hello/you">/hello/you</router-link></li>
        <li><router-link to="/static">/static</router-link></li>
        <li><router-link to="/dynamic/1">/dynamic/1</router-link></li>
        <li><router-link to="/attrs">/attrs</router-link></li>
      </ul>
      <router-view></router-view>
    </div>
複製代碼

13 路由懶加載

vue主要用於單頁面應用,此時webpack會打包大量文件,這樣就會形成首頁須要加載資源過多,首屏時間過長,給用戶一種不太友好的體驗. 若是使用路由懶加載,僅在你路由跳轉的時候才加載相關頁面.這樣首頁加載的東西少了,首屏時間也減小了. vueRouter的懶加載主要是靠Vue 的異步組件Webpack 的代碼分割功能,輕鬆實現路由組件的懶加載。 這裏寫法其實我在第5.3章裏的例子已經寫過,比較簡單隻須要將組件以promise形式引入便可.

routes:[
      path:'/',
      name:'HelloWorld',
      component:resolve=>require(['@/component/HelloWorld'],resolve)
  ]
  //此時HelloWorld組件則不須要在第一步import進來
複製代碼

13.1 把組件按組分塊

把組件按組分塊能夠把路由下的全部組件都打包在同個異步塊 (chunk) 中,而且在f12的network裏面看到動態加載的組件名字. 前提條件:

  • Webpack版本 > 2.4
  • 須要在webpack.base.conf.js裏面的output裏面的filename下面加上chunkFileName
output: {
 path: config.build.assetsRoot,
 filename: '[name].js',
 // 須要配置的地方
 chunkFilename: '[name].js',
 publicPath: process.env.NODE_ENV === 'production'
   ? config.build.assetsPublicPath
   : config.dev.assetsPublicPath
}
複製代碼

此時在引入組件時的寫法須要使用 命名 chunk,一個特殊的註釋語法來提供 chunk name

const Foo = () => import(/* webpackChunkName: "group-foo" */ './Foo.vue')
const Bar = () => import(/* webpackChunkName: "group-foo" */ './Bar.vue')
const Baz = () => import(/* webpackChunkName: "group-foo" */ './Baz.vue')
複製代碼

14 導航守衛

路由導航守衛,通俗點說就是路由鉤子.做用也和生命週期鉤子相似,在路由跳轉過程進行操做控制. 導航守衛有不少鉤子,這裏我就不照搬官方文檔了.這裏你們本身先點擊閱讀完導航守衛,而後再看個人總結和代碼例子.

14.1 導航守衛分類

  • 1,全局守衛::異步執行,每一個路由跳轉都會按順序執行.
    • router.beforeEach 全局前置守衛
    • router.beforeResolve 全局解析守衛(2.5.0+) 在beforeRouteEnter調用以後調用.
    • router.afterEach 全局後置鉤子 進入路由以後 注意:不支持next(),只能寫成這種形式router.afterEach((to, from) => {});

每一個守衛方法接收三個參數:

  • to: Route: 即將要進入的目標 路由對象

  • from: Route: 當前導航正要離開的路由對象

  • next: Function: 必定要調用該方法來 resolve 這個鉤子。執行效果依賴 next 方法的調用參數。

    • next(): 進行管道中的下一個鉤子。若是所有鉤子執行完了,則導航的狀態就是 confirmed (確認的)。

    • next(false): 中斷當前的導航。若是瀏覽器的 URL 改變了 (多是用戶手動或者瀏覽器後退按鈕),那麼 URL 地址會重置到 from 路由對應的地址。

    • next('/') 或者 next({ path: '/' }): 跳轉到一個不一樣的地址。當前的導航被中斷,而後進行一個新的導航。你能夠向 next 傳遞任意位置對象,且容許設置諸如 replace: truename: 'home' 之類的選項以及任何用在 router-link 的 to prop 或 router.push 中的選項。

    • next(error): (2.4.0+) 若是傳入 next 的參數是一個 Error 實例,則導航會被終止且該錯誤會被傳遞給 router.onError() 註冊過的回調。

官方介紹的比較簡單,沒有實際栗子,下面我就經過栗子再進行詳細的說明

//1,能夠在main.js 或者在單獨的路由配置文件router.js中進行設置
	router.beforeEach((to, from, next) => { 
	...
      next();
    });
	
//2,也能夠在組件內部設置
	this.$router.beforeEach((to, from, next) => { 
	...
      next();
    });
	
//3,對函數及next()的詳細使用說明
    router.beforeEach((to, from, next) => { 
	//首先to和from 實際上是一個路由對象,因此路由對象的屬性都是能夠獲取到的(具體能夠查看官方路由對象的api文檔).
	//例如:我想獲取獲取to的完整路徑就是to.path.獲取to的子路由to.matched[0].
      next();//使用時,千萬不能漏寫next!!!
	//next() 表示直接進入下一個鉤子.
	//next(false) 中斷當前導航
	//next('/path路徑')或者對象形式next({path:'/path路徑'}) 跳轉到path路由地址
	//next({path:'/shotcat',name:'shotCat',replace:true,query:{logoin:true}...}) 這種對象的寫法,能夠往裏面添加不少.router-link 的 to prop 和 router.push 中的選項(具體能夠查看api的官方文檔)全都是能夠添加進去的,再說明下,replace:true表示替換當前路由地址,經常使用於權限判斷後的路由修改.
	//next(error)的用法,(需2.4.0+) 
    }).catch(()=>{
  //跳轉失敗頁面
  next({ path: '/error', replace: true, query: { back: false }})
})
//若是你想跳轉報錯後,再回調作點其餘的可使用 router.onError()
router.onError(callback => { 
      console.log('出錯了!', callback);
    });
複製代碼
  • 2,路由獨享的守衛: 即路由對象獨享的守衛
    • beforeEnter:路由只獨享這一個鉤子,在rutes裏配置
const router = new VueRouter({
  routes: [
    {
      path: '/foo',
      component: Foo,
      beforeEnter: (to, from, next) => {
        // 使用方法和上面的beforeEach一毛同樣
      }
    }
  ]
})
複製代碼
  • 3,組件內的守衛: 注意:這類路由鉤子是寫在組件內部的,
    • beforeRouteEnter 進入路由前,此時實例還沒建立,沒法獲取到zhis
    • beforeRouteUpdate (2.2) 路由複用同一個組件時
    • beforeRouteLeave 離開當前路由,此時能夠用來保存數據,或數據初始化,或關閉定時器等等

這裏官方的例子說明的很詳細,這裏就直接進行引用了.

//在組件內部進行配置,這裏的函數用法也是和beforeEach一毛同樣
const Foo = {
  template: `...`,
  beforeRouteEnter (to, from, next) {
    // 在渲染該組件的對應路由被 confirm 前調用
    // 不!能!獲取組件實例 `this`
    // 由於當守衛執行前,組件實例還沒被建立
  },
  beforeRouteUpdate (to, from, next) {
    // 在當前路由改變,可是該組件被複用時調用
    // 舉例來講,對於一個帶有動態參數的路徑 /foo/:id,在 /foo/1 和 /foo/2 之間跳轉的時候,
    // 因爲會渲染一樣的 Foo 組件,所以組件實例會被複用。而這個鉤子就會在這個狀況下被調用。
    // 能夠訪問組件實例 `this`
  },
  beforeRouteLeave (to, from, next) {
    // 導航離開該組件的對應路由時調用
    // 能夠訪問組件實例 `this`
  }
}
複製代碼

14.2 完整的導航解析流程

官方文檔給的說明都是文字形式的,不是特別直觀.這裏就不copy了.這裏就直接以流程圖的形式進行展現(這裏參考了這位同窗的圖,在此感謝!).

導航解析流程

15 路由元信息

15.1 什麼是路由元信息

一句話歸納:路由配置的meta對象裏的信息. 官方栗子:

const router = new VueRouter({
  routes: [
    {
      path: '/foo',
      component: Foo,
      children: [
        {
          path: 'bar',
          component: Bar,
          // a meta field
          meta: { requiresAuth: true }
        }
      ]
    }
  ]
})
複製代碼

從栗子能夠看出就是給路由添加了一個自定義的meta對象,並在裏面設置了一個requiresAuth狀態爲true.

15.2 它有什麼用

從下面的另外一個官方栗子裏已經給出了答案.

router.beforeEach((to, from, next) => {
  if (to.matched.some(record => record.meta.requiresAuth)) {
    //對matched不瞭解的建議看官方api文檔,或我7.1節的說明
	//數組some方法,若是meta.requiresAuth爲ture,則返回true.此時,說明進入該路由前須要判斷用戶是否已經登陸 
    if (!auth.loggedIn()) {   //若是沒登陸,則跳轉到登陸頁
      next({
        path: '/login',
        query: { redirect: to.fullPath }  //官方例子的這個小細節很好,經過query將要跳轉的路由路徑保存下來,待完成登陸後,就能夠直接獲取該路徑,直接跳轉到登陸前要去的路由
      })
    } else {
      next()
    }
  } else {
    next() // 確保必定要調用 next()
  }
})
複製代碼

咱們能夠經過在meta裏設置的狀態,來判斷是否須要進行登陸驗證.若是meta裏的requiresAuth爲true,則須要判斷是否已經登陸,沒登陸就跳轉到登陸頁.若是已登陸則繼續跳轉.

此時,可能會有同窗說,前面說的path,params,query均可以存儲信息,做爲登陸驗證的狀態標記.的確,它們也能夠達到一樣的效果.若是是少許單個的驗證,使用它們問題不大. 但若是是多個路由都須要進行登陸驗證呢?path,params,query是把信息顯性地存儲在url上的.而且多個路徑都把一個相同的狀態信息加在url上.這樣就使url再也不單純,而且也很不優雅美觀. 因此要優雅要隱性地傳遞信息,就使用meta對象吧!

16 滾動行爲

當年切換路由時,可使頁面滾動到你想要的某個地方,或者是保持以前滾動的位置,這時你就須要使用scrollBehavior這個方法.

注意點:

  • 這裏控制和記住的滾動位置都是僅對整個組件頁面而言的,並不包含你組件裏面其餘的滾動條.
  • 這裏路由的模式只能是history.由於它使用了History新增的pushState().具體能夠看我第6章的說明.
const router = new VueRouter({
mode:'history',//這個不能忘,默認是hash模式
  routes: [...],
  scrollBehavior (to, from, savedPosition) {
     // to:要進入的目標路由對象,到哪裏去.和導航守衛的beforeEach同樣
	 //from:離開的路由對象,哪裏來
	 //savedPosition: 點擊前進/後退的時候記錄值{x:?,y:?}.而且只有經過瀏覽器的前進後退纔會觸發.
    // return 指望滾動到哪一個的位置 { x: number, y: number }或者是{ selector: string, offset? : { x: number, y: number }},這裏selector接收字符串形式的hash,如'#foo',同時你還能夠經過offset設置偏移,版本須要大於2.6+
	//舉個實例
	if(savePosition) { //若是是瀏覽器的前進後退就,返回以前保存的位置
      return savePosition;
    }else if(to.hash) {//若是存在hash,就滾動到hash所在位置
      return {selector: to.hash}
    }else{
	  return {x:0,y:0}//不然就滾動到頂部
	}
  }
})
複製代碼
相關文章
相關標籤/搜索