vue——Router簡介
- vue-router是Vue.js官方的路由插件,它和vue.js是深度集成的,適合用於構建單頁面應用。
- vue的單頁面應用是基於路由和組件的,路由用於設定訪問路徑,並將路徑和組件映射起來。
- 傳統的頁面應用,是用一些超鏈接來實現頁面切換和跳轉的。在vue-router單頁面應用中,則是路徑之間的切換,也就是組件的切換
1.動態路由匹配
定義路由
export default new Router({
routes: [
{
path: '/BookDetails/:book_id',
name: 'BookDetails',
component: BookDetails
},
{
path: '/BookDetailsTwo/user/:username/book/:book_id',
name: 'BookDetailsTwo',
component: BookDetailsTwo
},
]
})
頁面
<template>
<div class="book">
<router-link :to="{ name:'BookDetails',params: { book_id: 1}}">跳轉書籍詳情\^o^/</router-link><br/><br/><br/>
<router-link :to="{ name:'BookDetailsTwo',params: { book_id: 1,username: '小嘟嘟'}}">跳轉高級書籍詳情┗|`O′|┛</router-link>
</div>
</template>
橋豆麻袋(~ ̄▽ ̄)~,對<router-link>
感興趣的可以去看 官網 ,或者 小姐姐(●'◡'●) 的博客,然后go on
點擊跳轉后的路由
http://localhost:8080/#/BookDetails/1
http://localhost:8080/#/BookDetailsTwo/user/小嘟嘟/book/1
跳轉的頁面接收路由參數(以第二個跳轉為例)
<template>
<div>
<div>人員姓名:{{$route.params.username }}</div>
<div>書籍Id:{{$route.params.book_id }}</div>
</div>
</template>
1-1響應路由參數的變化
提醒一下,當使用路由參數時,例如從 /BookDetails/1 導航到 /BookDetails/2,原來的組件實例會被復用。因為兩個路由都渲染同個組件,比起銷毀再創建,復用則顯得更加高效。不過,這也意味着組件的生命周期鈎子不會再被調用。
BookDetails組件
<template>
<div class="book-details">
<div>書籍詳情 Id:{{ $route.params.book_id }}</div><br/><br/>
<router-link :to="{ name:'BookDetails',params: { book_id: 2}}">自己跳自己o(* ̄▽ ̄*)ブ</router-link>
</div>
</template>
<script>
export default {
data () {
return {
}
},
created(){
console.log('進入圖書詳情~~~')
}
}
</script>
當從父頁面跳轉過來時會執行生命周期,當點擊組件里‘自己跳自己’時,並不會觸發生命周期
當然有解決方法,還是兩種(●ˇ∀ˇ●)
方法一(使用watch (監測變化) $route 對象)
BookDetails組件
<template>
<div class="book-details">
<div>書籍詳情 Id:{{ $route.params.book_id }}</div><br/><br/>
<router-link :to="{ name:'BookDetails',params: { book_id: 2}}">自己跳自己o(* ̄▽ ̄*)ブ</router-link>
</div>
</template>
<script>
export default {
data () {
return {
}
},
created(){
console.log('進入圖書詳情~~~')
},
watch:{
'$route'(to, from) {
console.log(to ,from, '路由監聽')
}
}
}
</script>
方法二(使用beforeRouteUpdate 導航守衛)
BookDetails組件
<template>
<div class="book-details">
<div>書籍詳情 Id:{{ $route.params.book_id }}</div><br/><br/>
<router-link :to="{ name:'BookDetails',params: { book_id: 2}}">自己跳自己o(* ̄▽ ̄*)ブ</router-link>
</div>
</template>
<script>
export default {
data () {
return {
}
},
created(){
console.log('進入圖書詳情~~~')
},
beforeRouteUpdate(to, from, next){
console.log(to, from, next,'導航守衛')
next()
},
watch:{
'$route'(to, from) {
console.log(to ,from, '路由監聽')
}
}
}
</script>
注意!!!用beforeRouteUpdate記得要寫next(),否則不會跳轉路由
1-2捕獲所有路由或 404 Not found 路由
在上面定義好的路由最后面添加新的路由
{
path: '/Fruits*',
name: 'FruitsBanana',
component: FruitsBanana
},
{
path: '*',
name: 'NotFound',
component: NotFound
}
當使用通配符路由時,請確保路由的順序是正確的,也就是說含有通配符的路由應該放在最后。路由 { path: '*' } 通常用於客戶端 404 錯誤
當我們輸入路由
http://localhost:8080/#/FruitsApple
會匹配到‘/Fruits*’,所以會跳轉到FruitsBanana組件
再次輸入路由
http://localhost:8080/#/IAmVeryHappy
這時候就會匹配到 ‘*’, 自然就進入到了寫好的404頁面(~ ̄▽ ̄)~
1-3高級匹配模式
vue-router 使用 path-to-regexp 作為路徑匹配引擎,所以支持很多高級的匹配模式,例如:可選的動態路徑參數、匹配零個或多個、一個或多個,甚至是自定義正則匹配。
舉個栗子(~ ̄▽ ̄)~
// 第一種(通過?的使用可以將參數變為可選項)
{
path: '/PathToRegexp/:id?',
name: 'PathToRegexp',
component: PathToRegexp
}
// 第二種(使用正則,只匹配id是數字)
{
path: '/PathToRegexp/:id(\\d+)',
name: 'PathToRegexp',
component: PathToRegexp
}
更多高級匹配
1-4匹配優先級
有時候,同一個路徑可以匹配多個路由,此時,匹配的優先級就按照路由的定義順序:誰先定義的,誰的優先級就最高。
定義路由
{
path: '/Fruits*',
name: 'FruitsBanana',
component: FruitsBanana
},
{
path: '/Fruits*',
name: 'FruitsPear',
component: FruitsPear
}
如上面所示,誰先定義的,誰的優先級就最高,只要匹配成功,就會進入到FruitsBanana組件
2.嵌套路由
Vue會自帶一個
是最頂層的出口,渲染最高級路由匹配到的組件。同樣地,一個被渲染組件同樣可以包含自己的嵌套
吶,現在來改變一下路由
{
path: '/Fruits',
name: 'Fruits',
component: Fruits,
children: [
{
path: 'Apple',
name: 'Apple',
component: Apple
},
{
path: 'Grape',
name: 'Grape',
component: Grape
},
]
}
組件
<template>
<div>
我是水果頁面<br/><br/><br/>
<router-link :to="{ name:'Apple'}">蘋果🍎</router-link><br/><br/><br/>
<router-link :to="{ name:'Grape'}">葡萄🍇</router-link><br/><br/><br/>
<router-view></router-view>
</div>
</template>
當我們訪問
http://localhost:8080/#/Fruits/Apple
http://localhost:8080/#/Fruits/Grape
就會更改組件里面<router-view></router-view>
的容
but當我們訪問
http://localhost:8080/#/Fruits
的時候<router-view></router-view>
是沒用內容的(T_T)
解決方法
{
path: '/Fruits',
name: 'Fruits',
component: Fruits,
children: [
{
path:'',
component: Strawberry
},
{
path: 'Apple',
name: 'Apple',
component: Apple
},
{
path: 'Grape',
name: 'Grape',
component: Grape
},
]
}
沒錯加一個空的path,這時候訪問
http://localhost:8080/#/Fruits
<router-view></router-view>
就會顯示Strawberry組件的內容(●ˇ∀ˇ●)
3.編程式的導航
除了使用<router-link>
創建 a 標簽來定義導航鏈接,我們還可以借助 router 的實例方法,通過編寫代碼來實現。
router.push(location, onComplete?, onAbort?)
注意:在 Vue 實例內部,你可以通過 $router 訪問路由實例。因此你可以調用 this.$router.push。
想要導航到不同的 URL,則使用 router.push 方法。這個方法會向 history 棧添加一個新的記錄,所以,當用戶點擊瀏覽器后退按鈕時,則回到之前的 URL。
當你點擊
聲明式 | 編程式 |
---|---|
<router-link :to="..."> |
router.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' }})
注意:如果提供了 path
,params
會被忽略,上述例子中的 query
並不屬於這種情況。取而代之的是下面例子的做法,你需要提供路由的 name
或手寫完整的帶有參數的 path
const userId = '123'
router.push({ name: 'user', params: { userId }}) // -> /user/123
router.push({ path: `/user/${userId}` }) // -> /user/123
// 這里的 params 不生效
router.push({ path: '/user', params: { userId }}) // -> /user
同樣的規則也適用於 router-link 組件的 to 屬性。
router.replace(location, onComplete?, onAbort?)
跟 router.push 很像,唯一的不同就是,它不會向 history 添加新記錄,而是跟它的方法名一樣 —— 替換掉當前的 history 記錄
聲明式 | 編程式 |
---|---|
<router-link :to="..." replace> |
router.replace(...) |
router.go(n)
這個方法的參數是一個整數,意思是在 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)
4.命名路由
有時候,通過一個名稱來標識一個路由顯得更方便一些,特別是在鏈接一個路由,或者是執行一些跳轉的時候。你可以在創建 Router 實例的時候,在 routes 配置中給某個路由設置名稱。
路由
{
path: '/user/:userId',
name: 'user',
component: User
}
用法
<router-link :to="{ name: 'user', params: { userId: 123 }}">User</router-link>
或者
router.push({ name: 'user', params: { userId: 123 }})
5.命名視圖
首先來定義頁面
<template>
<div id="app">
<router-view/>
<router-view name="fruits"/>
<router-view name="animal"/>
</div>
</template>
路由
{
path: '/',
components: {
default: Food, // 默認視圖
fruits:Pineapple,
animal:Cat
}
}
當我們訪問路由
http://localhost:8081/#/
的時候,會渲染視圖對應的組件
嵌套命名視圖
定義Food組件
<template>
我是Food
<router-view/>
<router-view name="animal"/>
</template>
定義路由
{
path: '/',
component: Food,
children: [
{
path: 'Milk',
component: Milk
},
{
path: 'Cat',
components: {
default: Fish,
animal: Cat
}
}
]
}
訪問路由
http://localhost:8081/#/Milk
// 渲染對應的 Milk 組件
http://localhost:8081/#/Cat
// 渲染對應的 Fish、Cat 組件
有時候我們項目會有一個始終存在的導航欄,但是呢,登錄頁又不需要,這時候就可以使用命名視圖
6.重定向和別名
重定向(redirect)
路由
{
path: '/Fruits',
name: 'Fruits',
component: Fruits,
redirect: '/Fruits/Apple'
children: [
{
path: 'Apple',
name: 'Apple',
component: Apple
},
{
path: 'Grape',
name: 'Grape',
component: Grape
},
]
}
當我們訪問
http://localhost:8080/#/Fruits
的時候,對自動跳轉到
http://localhost:8080/#/Fruits/Apple
注意!!!
上面有寫到
{
path: '/Fruits',
name: 'Fruits',
component: Fruits,
children: [
{
path:'',
component: Strawberry
},
{
path: 'Apple',
name: 'Apple',
component: Apple
},
{
path: 'Grape',
name: 'Grape',
component: Grape
}
]
},
其中
{
path:'',
component: Strawberry
}
// 不會改變路由,只是會把<router-view/>默認顯示到Strawberry組件
redirect: '/Fruits/Apple'
// 會改變路由到Apple
是不一樣的
重定向的目標也可以是一個命名的路由
{
path: '/Fruits',
name: 'Fruits',
component: Fruits,
redirect: {name: 'Apple'},
children: [
{
path: 'Apple',
name: 'Apple',
component: Apple
},
{
path: 'Grape',
name: 'Grape',
component: Grape
},
]
}
當我們訪問
http://localhost:8080/#/Fruits
的時候,對自動跳轉到
http://localhost:8080/#/Fruits/Apple
甚至是一個方法,動態返回重定向目標
{
path: '/Fruits',
redirect: to => {
// 方法接收 目標路由 作為參數
// return 重定向的 字符串路徑/路徑對象
}
}
這個就不細講了,感興趣的可以看這里呦
別名(alias)
/Fruits 的別名是 /b,意味着,當用戶訪問 /b 時,URL 會保持為 /b,但是路由匹配則為 /Fruits,就像用戶訪問 /Fruits 一樣
{
path: '/Fruits',
name: 'Fruits',
component: Fruits,
alias: '/b'
}
當訪問
http://localhost:8080/#/b
實際上是訪問的
http://localhost:8080/#/Fruits
但地址是不會變成/Fruits
當然它也有高級的玩法,感興趣的可以看這里呦
7.路由組件傳參
在組件中使用 $route 會使之與其對應路由形成高度耦合,從而使組件只能在某些特定的 URL 上使用,限制了其靈活性。
使用 props 將組件和路由解耦
路由
{
path: '/BookDetails/:book_id',
name: 'BookDetails',
component: BookDetails,
props: true
}
BookDetails組件
<template>
<div class="book-details">
{{book_id}}
</div>
</template>
<script>
export default {
props: ['book_id'],
data () {
return {
}
}
}
</script>
布爾模式
在路由配置中設置 props: true 時默認將 $route.params 數據傳給組件,組件需要通過自身的 props 屬性取出 params 中的屬性
對象模式
如果 props 是一個對象,其下所有屬性均會被傳入組件。需要注意的是當 props 必須是是靜態的
路由
{
path: '/BookDetails/:book_id',
name: 'BookDetails',
component: BookDetails,
props: {
name: 'lucky',
id: 7
}
}
BookDetails組件
<template>
<div class="book-details">
{{name + id}}
</div>
</template>
<script>
export default {
props: ['name', 'id'],
data () {
return {
}
}
}
</script>
函數模式
路由
{
path: '/BookDetails',
name: 'BookDetails',
component: BookDetails,
props: (route) => ({ book_id: route.query.book_id })
}
父組件
<template>
<div class="book">
<button @click="goRouter">函數模式</button>
</div>
</template>
<script>
export default {
data () {
return {
}
},
methods:{
goRouter(){
this.$router.push({path: 'BookDetails', query: {book_id: 999}})
},
}
}
</script>
沒錯它也有高級的玩法,感興趣的可以看這里呦
8.HTML5 History 模式
vue-router
默認 hash 模式 —— 使用 URL 的 hash 來模擬一個完整的 URL,於是當 URL 改變時,頁面不會重新加載。如果不想要很丑的 hash,我們可以用路由的 history 模式,這種模式充分利用 history.pushState API 來完成 URL 跳轉而無須重新加載頁面
路由
export default new Router({
mode: 'history',
routes: [...]
})
來看一下用之前和用之后的地址(~ ̄▽ ̄)~
// hash
http://localhost:8080/#/
http://localhost:8080/#/BookDetails/1
// history
http://localhost:8080/
http://localhost:8080/BookDetails/1
emmmmmmmmm 好看了。。。 (✿◕‿◕✿)
but
不過這種模式要玩好,還需要后台配置支持。因為我們的應用是個單頁客戶端應用,如果后台沒有正確的配置,當用戶在瀏覽器直接訪問
http://oursite.com/BookDetails/id
就會返回 404,這就不好看了
啊哈,后台怎么配置呢?自己去看吧,我不知道(~ ̄▽ ̄)~