vue-router 路由 總結

vue.js 路由基礎

安裝vue - router

直接下載 / CDN

https://unpkg.com/vue-router/...html

Unpkg.com 提供了基於 NPM 的 CDN 連接。上面的連接會一直指向在 NPM 發佈的最新版本。你也能夠像 https://unpkg.com/vue-router@... 這樣指定 版本號 或者 Tag。vue

在 Vue 後面加載 vue-router,它會自動安裝的:vue-router

<script src="/path/to/vue.js"></script>
<script src="/path/to/vue-router.js"></script>

NPM

npm install vue-router

若是在一個模塊化工程中使用它,必需要經過 Vue.use() 明確地安裝路由功能:npm

import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

若是使用全局的 script 標籤,則無須如此(手動安裝)。編程

Getting Started

教程中的案例代碼將使用 ES2015 來編寫。瀏覽器

用 Vue.js + vue-router 建立單頁應用,是很是簡單的。使用 Vue.js ,咱們已經能夠經過組合組件來組成應用程序,當你要把 vue-router 添加進來,咱們須要作的是,將組件(components)映射到路由(routes),而後告訴 vue-router 在哪裏渲染它們。app

341820-20160721065509466-1679223492.png

JavaScript

1建立組件:建立單頁面應用須要渲染的組件

2建立路由:建立VueRouter實例

3映射路由:調用VueRouter實例的map方法

4啓動路由:調用VueRouter實例的start方法

HTML

使用v-link指令

使用<router-view>標籤

router.redirect

應用在首次運行時右側是一片空白,應用一般都會有一個首頁,例如:Home頁。
使用router.redirect方法將根路徑重定向到/home路徑:ide

router.redirect({

    '/': '/home'
    
})

router.redirect方法用於爲路由器定義全局的重定向規則,全局的重定向會在匹配當前路徑以前執行。模塊化

動態路由的匹配

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

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

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

如今呢,像 /user/foo 和 /user/bar 都將映射到相同的路由。

一個『路徑參數』使用冒號 : 標記。當匹配到一個路由時,參數值會被設置到 this.$route.params,能夠在每一個組件內使用。因而,咱們能夠更新 User 的模板,輸出當前用戶的 ID:

const User = {
  template: '<div>User {{ $route.params.id }}</div>'
}

你能夠在一個路由中設置多段『路徑參數』,對應的值都會設置到 $route.params 中。例如:

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

除了 $route.params 外,$route 對象還提供了其它有用的信息,例如,$route.query(若是 URL 中有查詢參數)、$route.hash 等等。你能夠查看 API 文檔 的詳細說明。

響應路由參數的變化

提醒一下,當使用路由參數時,例如從 /user/foo 導航到 user/bar,原來的組件實例會被複用。由於兩個路由都渲染同個組件,比起銷燬再建立,複用則顯得更加高效。不過,這也意味着組件的生命週期鉤子不會再被調用。

複用組件時,想對路由參數的變化做出響應的話,你能夠簡單地 watch(監測變化) $route 對象:

const User = {
  template: '...',
  watch: {
    '$route' (to, from) {
      // 對路由變化做出響應...
    }
  }
}

高級匹配模式

vue-router 使用 path-to-regexp 做爲路徑匹配引擎,因此支持不少高級的匹配模式,例如:可選的動態路徑參數、匹配零個或多個、一個或多個,甚至是自定義正則匹配。查看它的 文檔 學習高階的路徑匹配,還有 這個例子 展現 vue-router 怎麼使用這類匹配。

嵌套路由

341820-20160721065511966-1246199297.png

嵌套路由是個常見的需求,假設用戶可以經過路徑/home/news和/home/message訪問一些內容,一個路徑映射一個組件,訪問這兩個路徑也會分別渲染兩個組件。

實現嵌套路由有兩個要點:

  • 在組件內部使用<router-view>標籤
  • 在路由器對象中給組件定義子路由

藉助 vue-router,使用嵌套路由配置,就能夠很簡單地表達這種關係。

接着上節建立的 app:

<div id="app">
  <router-view></router-view>
</div>
const User = {
  template: '<div>User {{ $route.params.id }}</div>'
}

const router = new VueRouter({
  routes: [
    { path: '/user/:id', component: User }
  ]
})

這裏的 <router-view> 是最頂層的出口,渲染最高級路由匹配到的組件。一樣地,一個被渲染組件一樣能夠包含本身的嵌套 <router-view>。例如,在 User 組件的模板添加一個 <router-view>:

const User = {
  template: `
    <div class="user">
          <h2>User {{ $route.params.id }}</h2>
          <router-view></router-view>
    </div>
}

要在嵌套的出口中渲染組件,須要在 VueRouter 的參數中使用 children 配置:

const router = new VueRouter({
  routes: [
    { path: '/user/:id', component: User,
      children: [
        {
          // 當 /user/:id/profile 匹配成功,
          // UserProfile 會被渲染在 User 的 <router-view> 中
          path: 'profile',
          component: UserProfile
        },
        {
          // 當 /user/:id/posts 匹配成功
          // UserPosts 會被渲染在 User 的 <router-view> 中
          path: 'posts',
          component: UserPosts
        }
      ]
    }
  ]
})

編程式的導航

除了使用router-link建立標籤a還能夠經過router的實例方法,經過編碼來實現.

如下兩種方式均可以建立一個a標籤:

  • <router-link to="...">
  • or
  • router.push(...)

    router.push向history棧中添加一條數據,用戶點擊back時,回到原來的url

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'}})

router.replace(location) 跟 router.push 很像,惟一的不一樣就是,它不會向 history 添加新記錄,而是跟它的方法名同樣 —— 替換掉當前的 history 記錄。

<router-link to="..." replace>  router.replace(...)

router.go(n) 方法的參數是一個整數,在 history 記錄中向前或者後退多少步

命名路由

SouthEast

有時候,經過一個名稱來標識一個路由顯得更方便一些,特別是在連接一個路由,或者是執行一些跳轉的時候。你能夠在建立 Router 實例的時候,在 routes 配置中給某個路由設置名稱。

const router = new VueRouter({
  routes: [
    {
      path: '/user/:userId',
      name: 'user',
      component: User
    }
  ]
})

要連接到一個命名路由,能夠給 router-link 的 to 屬性傳一個對象:

<router-link :to="{ name: 'user', params: { userId: 123 }}">User</router-link>

這跟代碼調用 router.push() 是一回事:

router.push({ name: 'user', params: { userId: 123 }})

這兩種方式都會把路由導航到 /user/123 路徑。

命名視圖

有時候想同時(同級)展現多個視圖,而不是嵌套展現,例如建立一個佈局,有 sidebar(側導航) 和 main(主內容) 兩個視圖,這個時候命名視圖就派上用場了。你能夠在界面中擁有多個單獨命名的視圖,而不是隻有一個單獨的出口。若是 router-view 沒有設置名字,那麼默認爲 default。

<router-view class="view one"></router-view>

<router-view class="view two" name="a"></router-view>

<router-view class="view three" name="b"></router-view>

一個視圖使用一個組件渲染,所以對於同個路由,多個視圖就須要多個組件。確保正確使用 components 配置(帶上 s):

const router = new VueRouter({
  routes: [
    {
      path: '/',
      components: {
        default: Foo,
        a: Bar,
        b: Baz
      }
    }
  ]
})

重定向和別名

重定向

重定向也是經過 routes 配置來完成,下面例子是從 /a 重定向到 /b:

const router = new VueRouter({
  routes: [
    { path: '/a', redirect: '/b' }
  ]
})

重定向的目標也能夠是一個命名的路由:

const router = new VueRouter({
  routes: [
    { path: '/a', redirect: { name: 'foo' }}
  ]
})

甚至是一個方法,動態返回重定向目標:

const router = new VueRouter({
  routes: [
    { path: '/a', redirect: to => {
      // 方法接收 目標路由 做爲參數
      // return 重定向的 字符串路徑/路徑對象
    }}
  ]
})

別名

『重定向』的意思是,當用戶訪問 /a時,URL 將會被替換成 /b,而後匹配路由爲 /b,那麼『別名』又是什麼呢?

/a 的別名是 /b,意味着,當用戶訪問 /b 時,URL 會保持爲 /b,可是路由匹配則爲 /a,就像用戶訪問 /a 同樣。

上面對應的路由配置爲:

const router = new VueRouter({
  routes: [
    { path: '/a', component: A, alias: '/b' }
  ]
})

『別名』的功能讓你能夠自由地將 UI 結構映射到任意的 URL,而不是受限於配置的嵌套路由結構。

HTML5 History 模式

項目中我用的是history模式。

默認 hash 模式 —— 使用 URL 的 hash 來模擬一個完整的 URL,因而當 URL 改變時,頁面不會從新加載。

若是不想要很醜的 hash,咱們能夠用路由的 history 模式,這種模式充分利用 history.pushState API 來完成 URL 跳轉而無須從新加載頁面。

const router = new VueRouter({
  mode: 'history',
  routes: [...]
})

當你使用 history 模式時,URL 就像正常的 url,例如 http://yoursite.com/user/id,也好看!

不過這種模式要玩好,還須要後臺配置支持。由於咱們的應用是個單頁客戶端應用,若是後臺沒有正確的配置,當用戶在瀏覽器直接訪問 http://oursite.com/user/id 就會返回 404,這就很差看了。

因此呢,你要在服務端增長一個覆蓋全部狀況的候選資源:若是 URL 匹配不到任何靜態資源,則應該返回同一個 index.html 頁面,這個頁面就是你 app 依賴的頁面。

導航鉤子

vue-router 提供的導航鉤子主要用來攔截導航,讓它完成跳轉或取消。有多種方式能夠在路由導航發生時執行鉤子:全局的, 單個路由獨享的, 或者組件級的。

  • 全局鉤子

const router = new VueRouter({ ... })
router.beforeEach((to, from, next) => {
    // do something 
    next();
});

router.afterEach((to, from, next) => {
    console.log(to.path);
});

每一個鉤子方法接收三個參數:

  • to: Route : 即將要進入的目標 [路由對象]
  • from: Route : 當前導航正要離開的路由
  • next: Function : 必定要調用該方法來 resolve 這個鉤子。執行效果依賴 next方法的調用參數。

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

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

next('/') 或者 next({ path: '/' }): 跳轉到一個不一樣的地址。當前的導航被中斷,而後進行一個新的導航。

確保要調用 next方法,不然鉤子就不會被 resolved。

  • 組件內的鉤子

你能夠在路由組件內直接定義如下路由導航鉤子:

beforeRouteEnter

beforeRouteUpdate (2.2 新增)

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

beforeRouteEnter 鉤子 不能 訪問 this,由於鉤子在導航確認前被調用,所以即將登場的新組件還沒被建立。

不過,你能夠經過傳一個回調給 next來訪問組件實例。在導航被確認的時候執行回調,而且把組件實例做爲回調方法的參數。

beforeRouteEnter (to, from, next) {
  next(vm => {
    // 經過 `vm` 訪問組件實例
  })
}

你能夠 在 beforeRouteLeave 中直接訪問 this。這個 leave 鉤子一般用來禁止用戶在還未保存修改前忽然離開。能夠經過 next(false) 來取消導航。

路由元信息

圖片描述

<div id="app">
        <p>
            <router-link to="/foo">首頁</router-link>
            <router-link to="/bar">關於咱們</router-link>
            <router-link to="/user">帳戶中心</router-link>
            <router-link to="/user/pwd">密碼管理</router-link>
            <router-link to="/login">登陸</router-link>
            <input type="button" value="logout" @click="logout">
        </p>
        <router-view></router-view>
    </div>
    <template id="logintpl">
        <div>
            <input type="button" value="login" @click="login">
        </div> 
    </template>
    <script>
        var Foo = {
            template:"<div>我是首頁</div>"
        }
        var Bar = {
            template:"<div>我是關於咱們</div>"
        }
        var User = {
            template:"<div>我是帳戶中心<router-view></router-view></div>"
        }
        var Pwd = {
            template:"<div>我是密碼</div>"
        }
    
        var routes = [
            //我是首頁
            {path:"/foo" , component:Foo},
            //我是關於咱們
            {path:"/bar" , component:Bar},
            //我是帳戶中心
            {
                path:"/user" , 
                meta:{requireLogin:true},
                component:User,
                children:[
                    {
                        //我是密碼
                        path:"pwd" , 
                        meta:{requireLogin:true},
                        component:Pwd
                    }
                ]
            },
        
            //我是登陸
            {
                path:"/login" , 
                component:{
                    template:"#logintpl",
                    methods:{
                        login:function(){
                            isLogin = true
                        }
                    }
                }
                
            }
        ]
        var router = new VueRouter({
            routes
        })
        var isLogin = true ;
        router.beforeEach((to, from, next) => {
            if(to.meta.requireLogin&&!isLogin){
                next("/login")
            }else{
                next();
            }
        })
    
        var app = new Vue({
            el:"#app",
            router,
            methods:{
                logout:function(){
                    isLogin = false
                }
            }
        });
    </script>
相關文章
相關標籤/搜索