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>
上面的例子中用到了兩個標簽組件
- <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屬性都不需要寫(基路徑)了
- <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)航。