10. vue-router 路由詳解

vue2有著深度繼承的路由插件,即:vue-router,其中文的API地址。

vue-router與其他的路由(direactor、sammy)等不同,它是與vue2深度繼承的,所以路由也是針對vue組件的。

安裝

直接下載 / CDN 方式

Unpkg.com 提供了基于 NPM 的 CDN 鏈接。上面的鏈接會一直指向在 NPM 發(fā)布的最新版本。你也可以像https://unpkg.com/vue-router@2.0.0/dist/vue-router.js這樣指定 版本號 或者 Tag。在 Vue.js后面加載 vue-router.js,它會自動安裝的:

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

NPM 方式

npm install vue-router

如果在一個模塊化工程中使用它,必須要通過 Vue.use() 明確地安裝路由功能:

import Vue from 'vue'
import VueRouter from 'vue-router'
//vueRouter是vue的插件,所以需要使用use方法來加載
Vue.use(VueRouter)

如果使用全局的 script 標簽,則無須如此(手動安裝)。

1.入門例子

下面是一個簡單的入門例子,代碼如下:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>vue-router功能</title>
<script type="text/javascript" src="js/vue.2.1.0.js"></script>
<script type="text/javascript" src="js/vue-router.js"></script>
</head>
<body>

<div id="app">
  <h1 v-text="title"></h1>
  <p>
    <!-- 使用 router-link 組件來導(dǎo)航. -->
    <!-- 通過傳入 `to` 屬性指定鏈接. -->
    <!-- <router-link> 默認會被渲染成一個 `<a>` 標簽 使用標簽的好處是能在切換模式的時候,router-link會自動修改模式 -->
    <!--可以直接寫style、css、id等屬性,以及自定義的數(shù)據(jù)-->
    <router-link id='foolink' data-n='2222' to="/foo" tag="li" style='color:red' class='linkCls'>Go to Foo</router-link>
    <router-link to="/bar">Go to Bar</router-link>
    <router-link to="/bar/bar01">Go to Bar01</router-link>
  </p>
  <!-- 路由出口 -->
  <!-- 路由匹配到的組件將渲染在這里 -->
  <router-view></router-view>
</div>


<script type="text/javascript">
//如果在一個模塊化工程中使用它,必須要通過 Vue.use() 明確地安裝路由功能:
//VueRouter是vue的插件,所以在入口文件需要用vue的use方法加載Vuerouter
// Vue.use(VueRouter)

var router = new VueRouter({
    mode:'hash' //router的模式,分為history 、hash(默認)
    ,routes:[
        { path: '/foo', component: {template:'<div>foo</div>'} }
        ,{ path: '/bar', component: {template:'<div>bar</div>'} }
    ] 
})
//如果使用全局的 script 標簽,則無須如此(手動安裝)。
var vm = new Vue({
    el:'#app'
    ,router:router //通過vue配置中的router掛載router實例
    ,data:{
        title:'Hello vue-router'
    }
});
</script>
</body>
</html>

上面的例子中用到了兩個標簽組件

  1. <router-link> 即:API
    <router-link>組件支持用戶在具有路由功能的應(yīng)用中(點擊)導(dǎo)航。 通過 to屬性指定目標地址,默認渲染成帶有正確鏈接的 <a/> 標簽,可以通過配置 tag屬性生成別的標簽.。另外,當目標路由成功激活時,鏈接元素自動設(shè)置一個表示激活的 CSS 類名。另外,router-link可以直接添加class和style來寫樣式。
    <router-link>比起寫死的 <a href="...">會好一些,理由如下:
  • 無論是 HTML5 history 模式還是 hash 模式,它的表現(xiàn)行為一致,所以,當你要切換路由模式,或者在 IE9 降級使用 hash 模式,無須作任何變動。
  • 在 HTML5 history 模式下,router-link會攔截點擊事件,讓瀏覽器不在重新加載頁面。
  • 當你在 HTML5 history 模式下使用 base選項之后,所有的 to屬性都不需要寫(基路徑)了
  1. <router-view>:組件是一個 functional 組件,渲染路徑匹配到的視圖組件。<router-view>渲染的組件還可以內(nèi)嵌自己的 <router-view>,根據(jù)嵌套路徑,渲染嵌套組件。

2.動態(tài)路由匹配

我們經(jīng)常需要把某種模式匹配到的所有路由,全都映射到同個組件。例如,我們有一個 User組件,對于所有 ID 各不相同的用戶,都要使用這個組件來渲染。那么,我們可以在 vue-router的路由路徑中使用『動態(tài)路徑參數(shù)』
具體的demo代碼如下:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>vue-router功能 2 動態(tài)路由</title>
<script type="text/javascript" src="js/vue.2.1.0.js"></script>
<script type="text/javascript" src="js/vue-router.js"></script>
</head>
<body>

<div id="app">
    <h1 v-text="title"></h1>
    <p>
        <router-link to="/user">user list</router-link>
    </p>
    <router-view></router-view>
</div>


<script type="text/javascript">

//用戶列表組件
var UserList = Vue.extend({
    data:function(){
        return {
            title:'用戶列表'
            ,userList:[
                {id:'1',name:'louis screw'}
                ,{id:'2',name:'shirley wang'}
            ]
        }
    }
    ,template:'\
        <ul>\
            <li v-for="user in userList">\
                <router-link :to="{ path: \'/user/\'+user.id }">\
                    <span v-text="user.id"></span>\
                    <span v-text="user.name"></span>\
                </router-link>\
            </li>\
        </ul>\
    '
});

var User = Vue.extend({
    data:function(){
        return {
            title:'User的詳細頁面'
        }
    }
    ,watch: {
        '$route':function(to, from) {//監(jiān)控在當前組件中路由發(fā)生變化時執(zhí)行的函數(shù),如果/user/1 切換到 /user/2時就會執(zhí)行此方法
            console.log(to,from)
        }
    }
    ,template:'\
        <div>\
            <div v-text="title"></div>\
            <div>傳遞過來的用戶編號 {{ $route.params.id }}</div>\
        </div>\
    '
});

var router = new VueRouter({
    mode:'hash' //router的模式,分為history 、hash(默認)
    ,routes:[
         { path: '/', redirect: '/user' } //router的重定向方法
        ,{ path: '/user', component: UserList }
        ,{ path: '/user/:id', component: User }
    ]
});

//如果使用全局的 script 標簽,則無須如此(手動安裝)。
var vm = new Vue({
    el:'#app'
    ,router:router //通過vue配置中的router掛載router實例
    ,data:{
        title:'Hello vue-router'
    }
});

</script>
</body>
</html>

上述的例子中有兩個組件,UserList組件和User組件,在UserList組件中根據(jù)User的id切換User組件,并在User組件中得到uri傳遞過來的參數(shù)

2.1 獲取路由參數(shù)

一個『路徑參數(shù)』使用冒號 : 標記。當匹配到一個路由時,參數(shù)值會被設(shè)置到 this.$route.params,可以在每個組件內(nèi)使用。于是,在 User的模板,輸出當前用戶的 ID:

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

你可以在一個路由中設(shè)置多段『路徑參數(shù)』,對應(yīng)的值都會設(shè)置到 $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 中有查詢參數(shù))、$route.hash 等等。你可以查看 API 文檔 的詳細說明。

3.嵌套路由

實際生活中的應(yīng)用界面,通常由多層嵌套的組件組合而成。同樣地,URL 中各段動態(tài)路徑也按某種結(jié)構(gòu)對應(yīng)嵌套的各層組件。
具體的代碼如下:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>vue-router功能 3 嵌套路由</title>
<script type="text/javascript" src="js/vue.2.1.0.js"></script>
<script type="text/javascript" src="js/vue-router.js"></script>
</head>
<body>

<div id="app">
    <h1 v-text="title"></h1>
    <router-view></router-view>
</div>


<script type="text/javascript">

//用戶列表組件
var UserList = Vue.extend({
    data:function(){
        return {
            title:'用戶列表'
            ,userList:[
                {id:'1',name:'louis screw'}
                ,{id:'2',name:'shirley wang'}
            ]
        }
    }
    ,template:'\
        <div>\
            <ul>\
                <li v-for="user in userList">\
                    <router-link :to="{ path: \'/user/\'+user.id }">\
                        <span v-text="user.id"></span>\
                        <span v-text="user.name"></span>\
                    </router-link>\
                </li>\
            </ul>\
            <router-view></router-view>\
        </div>\
    '
});

var User = Vue.extend({
    data:function(){
        return {
            title:'User的詳細頁面'
        }
    }
    ,template:'\
        <div>\
            <div v-text="title"></div>\
            <div>傳遞過來的用戶編號 {{ $route.params.id }}</div>\
        </div>\
    '
});

var router = new VueRouter({
    mode:'hash' //router的模式,分為history 、hash(默認)
    ,routes:[
         { path: '/', redirect: '/user' } //router的重定向方法
        ,{ path: '/user'
            , component: UserList
            , children:[
                //要注意,以 / 開頭的嵌套路徑會被當作根路徑。 這讓你充分的使用嵌套組件而無須設(shè)置嵌套的路徑。
                // 當 /user/:id 匹配成功,子路由最好寫成相對父路由的寫法 或者 絕對全路徑的方法
                //path:'/user/:id' 和 path:':id' 最終的效果是一樣的
                {path:'/user/:id',component: User}
            ]
        }
    ]
});

//如果使用全局的 script 標簽,則無須如此(手動安裝)。
var vm = new Vue({
    el:'#app'
    ,router:router //通過vue配置中的router掛載router實例
    ,data:{
        title:'Hello vue-router'
    }
});

</script>
</body>
</html>

4.編程式的導(dǎo)航

除了使用 <router-link> 創(chuàng)建 a 標簽來定義導(dǎo)航鏈接,我們還可以借助 router 的實例方法,通過編寫代碼來實現(xiàn)。

4.1 router.push(location)

想要導(dǎo)航到不同的 URL,則使用 router.push 方法。這個方法會向 history 棧添加一個新的記錄,所以,當用戶點擊瀏覽器后退按鈕時,則回到之前的 URL。

當你點擊 <router-link> 時,這個方法會在內(nèi)部調(diào)用,所以說,點擊 <router-link :to="..."> 等同于調(diào)用 router.push(...)。

聲明式 編程式
<router-link :to="..."> router.push(...)

該方法的參數(shù)可以是一個字符串路徑,或者一個描述地址的對象。例如:

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

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

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

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

4.2 router.replace(location)

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

聲明式 編程式
<router-link :to="..." replace> router.replace(...)

4.3 router.go

這個方法的參數(shù)是一個整數(shù),意思是在 history 記錄中向前或者后退多少步,類似 window.history.go(n)。
例子

// 在瀏覽器記錄中前進一步,等同于 history.forward()
router.go(1)

// 后退一步記錄,等同于 history.back()
router.go(-1)

// 前進 3 步記錄
router.go(3)

// 如果 history 記錄不夠用,那就默默地失敗唄
router.go(-100)
router.go(100)

5.命名路由

有時候,通過一個名稱來標識一個路由顯得更方便一些,特別是在鏈接一個路由,或者是執(zhí)行一些跳轉(zhuǎn)的時候。你可以在創(chuàng)建 Router 實例的時候,在 routes 配置中給某個路由設(shè)置名稱。

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

要鏈接到一個命名路由,可以給 router-link 的 to 屬性傳一個對象:

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

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

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

這兩種方式都會把路由導(dǎo)航到 /user/123 路徑。

6.命名視圖

有時候想同時(同級)展示多個視圖,而不是嵌套展示,例如創(chuàng)建一個布局,有 sidebar(側(cè)導(dǎo)航) 和 main(主內(nèi)容) 兩個視圖,這個時候命名視圖就派上用場了。你可以在界面中擁有多個單獨命名的視圖,而不是只有一個單獨的出口。如果 router-view 沒有設(shè)置名字,那么默認為 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):

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

7.重定向

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

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

重定向的目標也可以是一個命名的路由:

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

甚至是一個方法,動態(tài)返回重定向目標:

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

8.導(dǎo)航鉤子

正如其名,vue-router 提供的導(dǎo)航鉤子主要用來攔截導(dǎo)航,讓它完成跳轉(zhuǎn)或取消。有多種方式可以在路由導(dǎo)航發(fā)生時執(zhí)行鉤子:全局的, 單個路由獨享的, 或者組件級的。

8.1全局鉤子

你可以使用 router.beforeEach 注冊一個全局的 before 鉤子:

var router = new VueRouter({ ... })
router.beforeEach(function(to,from,next){

});

當一個導(dǎo)航觸發(fā)時,全局的 before 鉤子按照創(chuàng)建順序調(diào)用。鉤子是異步解析執(zhí)行,此時導(dǎo)航在所有鉤子 resolve 完之前一直處于 等待中。

每個鉤子方法接收三個參數(shù):

  • to: Route: 即將要進入的目標 路由對象
  • from: Route: 當前導(dǎo)航正要離開的路由
  • next: Function: 一定要調(diào)用該方法來 resolve 這個鉤子。執(zhí)行效果依賴 next 方法的調(diào)用參數(shù)。
  • next(): 進行管道中的下一個鉤子。如果全部鉤子執(zhí)行完了,則導(dǎo)航的狀態(tài)就是 confirmed (確認的)。
  • next(false): 中斷當前的導(dǎo)航。如果瀏覽器的 URL 改變了(可能是用戶手動或者瀏覽器后退按鈕),那么 URL 地址會重置到 from 路由對應(yīng)的地址。
  • next('/') 或者 next({ path: '/' }): 跳轉(zhuǎn)到一個不同的地址。當前的導(dǎo)航被中斷,然后進行一個新的導(dǎo)航。

確保要調(diào)用 next 方法,否則鉤子就不會被 resolved。

同樣可以注冊一個全局的 after 鉤子,不過它不像 before 鉤子那樣,after 鉤子沒有 next 方法,不能改變導(dǎo)航:

router.afterEach(route => {
  // ...
})

8.2 某個路由獨享的鉤子

你可以在路由配置上直接定義 beforeEnter 鉤子:

var router = new VueRouter({
  routes: [
    {
      path: '/foo',
      component: Foo,
      beforeEnter: (to, from, next) => {
        // ...
      }
    }
  ]
})

這些鉤子與全局 before 鉤子的方法參數(shù)是一樣的。

8.3 組件內(nèi)的鉤子

最后,你可以使用 beforeRouteEnter 和 beforeRouteLeave,在路由組件內(nèi)直接定義路由導(dǎo)航鉤子,

var Foo = {
  template: `...`,
  beforeRouteEnter:function(to, from, next) {
    // 在渲染該組件的對應(yīng)路由被 confirm 前調(diào)用
    // 不!能!獲取組件實例 `this`
    // 因為當鉤子執(zhí)行前,組件實例還沒被創(chuàng)建
  },
  beforeRouteLeave:function(to, from, next) {
    // 導(dǎo)航離開該組件的對應(yīng)路由時調(diào)用
    // 可以訪問組件實例 `this`
  }
}

beforeRouteEnter 鉤子 不能 訪問 this,因為鉤子在導(dǎo)航確認前被調(diào)用,因此即將登場的新組件還沒被創(chuàng)建。

不過,你可以通過傳一個回調(diào)給 next來訪問組件實例。在導(dǎo)航被確認的時候執(zhí)行回調(diào),并且把組件實例作為回調(diào)方法的參數(shù)。

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

你可以 在 beforeRouteLeave 中直接訪問 this。這個 leave 鉤子通常用來禁止用戶在還未保存修改前突然離開??梢酝ㄟ^ next(false) 來取消導(dǎo)航。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容