vue2.X基礎知識八之vue-router路由
前端路由是直接找到與地址匹配的一個元件或物件並將其渲染出來。改變瀏覽器地址而不向伺服器發出請求有兩種做法,一是在地址中加入#以欺騙瀏覽器,地址的改變是由於正在進行頁內導航;二是使用HTML5的window.history功能,使用URL的Hash來模擬一個完整的URL。將單頁程式分割為各自功能合理的元件或者頁面,路由起到了一個非常重要的作用。它就是連線單頁程式中各頁面之間的鏈條。
一、在vue中引入vue-router
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
二、路由配置
Vue.js是沒有頁面這個概念的,Vue.js的容器就只有元件。但我們用vue-router配合元件又會重新形成各種的"頁面",我們可以這樣來約定和理解:
- 頁面是一個抽象的邏輯概念,用於劃分功能場景
元件是頁面在Vue的具體實現方式
vue-router提供了兩個指令標籤元件來處理這個導航與自動渲染邏輯:
- <router-view>——渲染路徑匹配的檢視元件,它還可以內嵌自己的<router-view>,根據巢狀路徑渲染巢狀元件。
- <router-link>——支援使用者再具有路由功能的應用中(點選)導航
例如,這裡有三個router-link連結
const App = { template: ·<ul> <li> <router-link to="/a">a</router-link> <ul> <li> <router-link to="/a/aa">aa</router-link> </li> </ul> </li> </ul>· }
const a = {
template: `<div>這裡是a
// 這裡是子路由aa顯示的地方
<router-view></router-view>
</div>`
};
const aa = {
template: `<div>這裡是a下面的子路由aa{{ $route.params }}</div>`
};
定義a路由及其子路由aa:
const router = new VueRouter({ routes: [ { path: '/a', component: a, // 子路由不需要'/' // 子路由顯示的地方 父級路由模板裡的第一個 router-view 標籤裡 children: [{ path: 'aa', component: aa }] }] })
vue-router提供了一種隱式的路由引用方式,vue-router將之稱為"命名路由",簡單點說就是通過路由的名稱引用取代URL的直接引用。如下所示:
const router = new VueRouter({
routes: [
{name: 'Home', path: '/', component: Home},
{
name: 'Me', path: '/me', component: Me
}
]
})
在<router-link>內通過名稱引用路由需要向to屬性傳入一個物件顯式宣告路由的名稱:
<router-link :to="{name: 'Home'}">
使用命名路由引用時採用的是:to 而不是to, 因為這個時候向<router-link>傳入的是一個物件{name:'Home'}而不是字串。
三、輸出指定元素
<router-link>元件支援使用者在具有路由功能的應用中(點選)導航。通過to屬性指定目標地址,預設渲染成帶有正確連結的<a>標籤。其實,我們並不需要輸出<a>元素標記,因為我們並沒有具體的連結地址,使用<li>元素同樣可以處理來自使用者的點選切換路由的事件。<router-link>可以通過配置tag屬性生成別的標籤,利用這個屬性我們可以直接輸出<li>而節省更多的程式碼:
<router-link :to="{ name: 'Home' }" tag="li"></router-link>
四、動態路由
將引數融入到路由的路徑定義之內成為路徑的一部分,是之更具有可讀性,我們稱這種引數為"動態路徑引數",具體的做法是在引數名之前加上“:”,然後將引數寫在路由的path內,具體定義如下:
routes: [
{
name: 'BookDetails',
// 這裡的 :id 就是動態路徑引數
path: '/books/:id',
component: BookDetails
}
]
在<router-link>中我們就可以加入一個params的屬性來指定具體的引數值:
<router-link :to="{name: 'BookDetails', params: { id: 1}}">
</router-link>
在元件中獲取這個id:
export default {
created () {
const bookID = this.$route.params.id
}
}
當使用路由引數時,例如從/books/1 導航到 /books/2,原來的元件例項會被複用。因為兩個路由都渲染同一個元件,比起銷燬再建立,複用顯得更加高效。不過,這也意味著元件的生命週期鉤子不會再被呼叫,也就是created、mounted等鉤子函式再頁面第二次載入時將失效。那麼,當複用元件時,想對路由引數的變化做出響應的話,就需要再watch物件內新增對$route物件變化的跟蹤函式:export default {
template: '',
watch: {
'$route' (to, from) {
// 對路由變化作出響應
}
}
}
$route.params定義的引數必然是整個路由的其中一個部分,vue-router還可以讓我們使用"/path?引數=值"的方式,也就是俗稱的查詢字串傳遞資料。如果要從$route中讀取Query string的引數,可以使用$route.query引數名的方式讀取。
<div>
<router-link :to="{ path: '/b', query: { id: 123 }}">/b/bb</router-link>
</div>
const b = Vue.component('b', {
template: `<div>這裡是b</div>`,
mounted () {
console.log(this.$route.query);
}
});
五、切頁動效
使用Vue提供的<transition></transition>封裝元件可以給任何元素和元件新增進入和退出的過渡效果。
有4個css類名在enter/leave的過渡中切換,以下是這4個類名的命名規則和作用。
- CSS類名-enter:定義進入過渡的開始狀態。在元素被插入時生效,在下一幀移除。
- CSS類名-enter-active: 定義進入過渡的結束狀態。在元素被插入時生效,在transition/animation完成之後移除。
- CSS類名-leave: 定義離開過渡的開始狀態。在離開過度被觸發時生效,在一個幀移除。
- CSS類名-leave-active: 定義離開過渡的結束狀態。在離開過渡被觸發時生效,在transition/animation完成之後移除。
<template>
<transition name="slide-fade">
<router-view></router-view>
</transition>
</template>
.slide-fade-enter-active {
transition: all .3s ease
}
.slide-fade-leave-active {
transition: all .3s cubic-bezier(1.0, 0.5, 0.8, 1.0);
}
.slide-fade-enter,
.slide-fade-leave-active {
transform: translateX(-430px)
opacity: 0
}
六、導航狀態樣式
在預設情況下當<router-link>對應的路由匹配成功時,就會自動設定class屬性值為.router-link-active,如果我們想要將“啟用”狀態樣式類命名為active,可以通過active-class屬性進行設定,例如:
<router-link :to="{ name: 'Home' }" tag="li" active-class="active">
<div>
<img src="xxx">
</div>
</router-link>
如果在頁面上都是這麼顯式宣告,那麼就需要在每個<router-link></router-link>元件元素上都要寫一次;我們還可以有另外一個選擇,就是在VueRouter的全域性配置上進行宣告,直接將.router-link-active這個預設值改為active,在main.js檔案內的VueRouter配置中加入以下語句:
const router = new VueRouter({
linkActiveClass: "active"
});
通過linkActiveClass全域性屬性就能進行統一的設定了。
6.1、精確匹配與包含匹配
<router-link>新增“啟用”狀態樣式類的預設依據是對URL地址的全包含匹配。舉個例子,如果當前的路徑是/home,那麼<router-link to="/">也會被匹配並設定CSS類名。
想要連結使用“精確匹配模式”,則使用exact屬性。在上面的例子中,“Home”路由就必須以精確匹配模式,否則它的tab被點選中之後,Home的tab會始終保持“啟用”狀態。
<!-- 這個連結只會在地址為/的時候被啟用 -->
<router-link :to="{name: 'Home'}" exact>
七、History的控制
當我們使用HTML5的History模式的時候,每次路由的改變都會被"推"到導航歷史中保留,在某些情況下我們不需要瀏覽器這樣做,而是希望它能將原有的記錄進行替換,那麼我們據需要了解<router-link>是如何通過程式設計方式控制路由進行導航的。首先Vue例項內有一個$router物件,這個物件會提供三個方法,<router-link>則是用兩種屬性來對應這三個方法的呼叫:
router的方法 | 屬性 | 說明 |
push() | - | 預設呼叫此方法 |
append() | append | 將目標URL追加到當前URL |
replace() | replace | 以目標URL替換現有的URL |
設定replace屬性的話,當點選時,會呼叫router.replace()而不是router.push(),於是導航後不會留下History記錄。
<router-link :to="{ name: 'Home'}" replace></router-link>
設定append屬性後,則在當前(相對)路徑前新增基路徑。例如,我們從/a導航到一個相對路徑b,如果沒有配置append,則路徑為/b,如果配置了,則為/a/b。
<router-link :to="{ path: 'relative/path'}" append></router-link>
八、關於Fallback
如果將路由配置為History模式,假如使用者點選Home上的<router-link>時,瀏覽器的位址列就會自動改變成對應的URL。如果我們直接在瀏覽器輸入http://localhost/home,你會驚奇的發現瀏覽器會出現404的錯誤!
這是由於直接在瀏覽器輸入http://localhost/home,瀏覽器就會直接將這個地址請求傳送至伺服器,先由伺服器處理路由,而客戶端路由的啟動條件是要訪問/index.html,所以,客戶端路由完全失效了!
解決的辦法是將所有發到伺服器的請求利用服務端的URLRewrite模板重新轉發給/index.html,啟動VueRouter進行處理,而瀏覽器位址列的URL保持不變。
當我們部署到生產環境時,就需要在web伺服器進行一些簡單配置以支援Fallback了。
Nginx
當出現404時將自動重定向至index.html
location / {
try_files $uri $uri/ /index.html;
}
本文內容摘抄自《vue2實踐揭祕》