目錄
- 1.vue-router 動態路由匹配
- 2.router-link組件及其屬性
- 3.vue-router路由的兩種模式
- 4.vue-router有哪幾種導航鉤子( 導航守衛 )?
- 5.完整的導航解析流程
- 6.vue-router實現路由懶加載( 動態加載路由 )參考http://www.lxweimin.com/p/a88a2ae4ebde
- 1. vue-router 動態路由匹配
我們經常需要把某種模式匹配到的所有路由,全都映射到同個組件。例如,我們有一個 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 文檔 的詳細說明。
- 2. router-link組件及其屬性
支持用戶在具有路由功能的應用中 (點擊) 導航 通過 to 屬性指定目標地址
一:router-link組件的props:
-
to
表示目標路由的鏈接。當被點擊后,內部會立刻把 to 的值傳到 router.push()
<router-link :to='/Home'>Home</router-link>
渲染結果:
<a href="Home">Home</a>
<router-link :to="{ path: 'register', query: { name: 'fjw' }}">router</router-link>
渲染結果:
<a href="/register?name=fjw">router</a>
-
tag:
指定<router-link>組件最終被渲染成什么標簽;非必須;如果沒有tag屬性,router-link最終會被渲染成a標簽。在上面的栗子中,渲染成了li標簽。
<router-link :to='/Home' tag="li" >Home</router-link>
渲染結果:
<li>Home</li>
此時依舊會監聽點擊事件,觸發導航
-
replace:
當點擊時,會調用 router.replace() 而不是 router.push(),于是導航后不會留下 history 記錄。
<router-link :to="{ path: '/abc'}" replace></router-link>
-
append:
則在當前 (相對) 路徑前添加基路徑。/a 導航到一個相對路徑 b,如果沒有配置 append,則路徑為 /b,如果配了,則為 /a/b
<router-link :to="{ path: 'relative/path'}" append></router-link>
-
active-class:
- 表示激活這個鏈接時,添加的class,默認是router-link-class。默認值可以通過路由的構造選項
linkActiveClass
來全局配置。
-
exact:
"是否激活" 默認類名的依據是 inclusive match (全包含匹配)。
<!-- 這個鏈接只會在地址為 / 的時候被激活 -->
<router-link to="/" exact>
-
event:
默認值: 'click' 聲明可以用來觸發導航的事件??梢允且粋€字符串或是一個包含字符串的數組。
-
exact-active-class:
默認值: "router-link-exact-active" 配置當鏈接被精確匹配的時候應該激活的 class。
- 3.vue-router路由的兩種模式mode
類型:
string
默認值:
"hash" (瀏覽器環境) | "abstract" (Node.js 環境)
-
可選值:
"hash" | "history" | "abstract"
配置路由模式:
hash
: 使用 URL hash 值來作路由。支持所有瀏覽器,包括不支持 HTML5 History Api 的瀏覽器。history
: 依賴 HTML5 History API 和服務器配置。查看 HTML5 History 模式。abstract
: 支持所有 JavaScript 運行環境,如 Node.js 服務器端。如果發現沒有瀏覽器的 API,路由會自動強制進入這個模式
-
hash模式:
url 的 hash 是以 # 開頭,原本是用來作為錨點,從而定位到頁面的特定區域。當 hash 改變時,頁面不會因此刷新,瀏覽器也不會向服務器發送請求。
http://www.xxx.com/#/home
同時, hash 改變時,并會觸發相應的 hashchange 事件。所以,hash 很適合被用來做前端路由。當 hash 路由發生了跳轉,便會觸發 hashchange 回調,回調里可以實現頁面更新的操作,從而達到跳轉頁面的效果。
hash模式的工作原理是hashchange事件,可以在window監聽hash的變化。我們在url后面隨便添加一個#xx觸發這個事件。
window.onhashchange = function(event){
console.log(event);
}
可以看到里邊有兩個屬性newURL和oldURL??梢酝ㄟ^模擬改變hsh的值,動態頁面數據。
<div id="test" style="height: 500px;width: 500px;margin: 0 auto"></div>
<script>
window.onhashchange = function(event){
let hash = location.hash.slice(1);
document.body.style.color = hash;
document.getElementById('test').style.backgroundColor = hash
}
</script>
盡管瀏覽器沒有請求服務器,但是頁面狀態和url已經關聯起來了,這就是所謂的前端路由,單頁應用的標配。
-
history模式:
HTML5 規范中提供了 history.pushState 和 history.replaceState 來進行路由控制。通過這兩個方法,可以實現改變 url 且不向服務器發送請求。同時不會像 hash 有一個 # ,更加的美觀。但是 History 路由需要服務器的支持,并且需將所有的路由重定向到根頁面。
History 路由的改變不會去觸發某個事件,所以我們需要去考慮如何觸發路由更新后的回調。
有以下兩種方式會改變 url:
- 調用 history.pushState 或 history.replaceState;
- 點擊瀏覽器的前進與后退。
第一個方式可以封裝一個方法,在調用 pushState(replaceState)后再調用回調。
function push (url) {
window.history.pushState({}, null, url);
handleHref();
}
function handleHref () {
console.log('render');
}
第二個方式,瀏覽器的前進與后退會觸發 popstate 事件。
window.addEventListener('popstate', handleHref);
前進,后退,跳轉操作方法:
history.go(-3);//后退3次
history.go(2);//前進2次
history.go(0);//刷新當前頁面
history.back(); //后退
history.forward(); //前進
這篇文章介紹的較為詳細,講到了實現原理https://juejin.im/post/5b330142e51d4558b10a9cc5
- 4.vue-router有哪幾種導航鉤子( 導航守衛 )?
vue-router 提供的導航守衛主要用來通過跳轉或取消的方式守衛導航。
例如判斷登錄信息:沒登錄全部跳到登錄頁。判斷必要操作是否進行沒進行的話中斷跳轉。
參數或查詢的改變并不會觸發進入/離開的導航守衛。你可以通過觀察 $route
對象來應對這些變化,或使用 beforeRouteUpdate
的組件內守衛。
分為三大類:全局守衛、路由守衛、組件守衛
[#]全局前置守衛
你可以使用 router.beforeEach 注冊一個全局前置守衛:
const router = new VueRouter({ ... })
router.beforeEach((to, from, next) => {
// ...
})
當一個導航觸發時,全局前置守衛按照創建順序調用。守衛是異步解析執行,此時導航在所有守衛 resolve 完之前一直處于 等待中。
每個守衛方法接收三個參數:
to: Route
: 即將要進入的目標 路由對象from: Route
: 當前導航正要離開的路由-
next: Function
: 一定要調用該方法來 resolve 這個鉤子。執行效果依賴next
方法的調用參數。next()
: 進行管道中的下一個鉤子。如果全部鉤子執行完了,則導航的狀態就是 confirmed (確認的)。next(false)
: 中斷當前的導航。如果瀏覽器的 URL 改變了 (可能是用戶手動或者瀏覽器后退按鈕),那么 URL 地址會重置到from
路由對應的地址。next('/')
或者next({ path: '/' })
: 跳轉到一個不同的地址。當前的導航被中斷,然后進行一個新的導航。你可以向next
傳遞任意位置對象,且允許設置諸如replace: true
、name: 'home'
之類的選項以及任何用在router-link
的to
prop 或router.push
中的選項。next(error)
: (2.4.0+) 如果傳入next
的參數是一個Error
實例,則導航會被終止且該錯誤會被傳遞給router.onError()
注冊過的回調。
確保要調用 next
方法,否則鉤子就不會被 resolved。
#全局解析守衛
在 2.5.0+ 你可以用 router.beforeResolve
注冊一個全局守衛。這和 router.beforeEach
類似,區別是在導航被確認之前,同時在所有組件內守衛和異步路由組件被解析之后,解析守衛就被調用。
#全局后置鉤子
你也可以注冊全局后置鉤子,然而和守衛不同的是,這些鉤子不會接受 next
函數也不會改變導航本身:
router.afterEach((to, from) => {
// ...
})
#路由獨享的守衛
你可以在路由配置上直接定義 beforeEnter
守衛:
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
}
}
]
})
這些守衛與全局前置守衛的方法參數是一樣的。
#組件內的守衛
最后,你可以在路由組件內直接定義以下路由導航守衛:
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` 訪問組件實例
})
}
注意 beforeRouteEnter
是支持給 next
傳遞回調的唯一守衛。對于 beforeRouteUpdate
和 beforeRouteLeave
來說,this
已經可用了,所以不支持傳遞回調,因為沒有必要了。
beforeRouteUpdate (to, from, next) {
// just use `this`
this.name = to.params.name
next()
}
這個離開守衛通常用來禁止用戶在還未保存修改前突然離開。該導航可以通過 next(false)
來取消。
beforeRouteLeave (to, from , next) {
const answer = window.confirm('Do you really want to leave? you have unsaved changes!')
if (answer) {
next()
} else {
next(false)
}
}
#完整的導航解析流程
- 導航被觸發。
- 在失活的組件里調用離開守衛。
- 調用全局的
beforeEach
守衛。 - 在重用的組件里調用
beforeRouteUpdate
守衛 (2.2+)。 - 在路由配置里調用
beforeEnter
。 - 解析異步路由組件。
- 在被激活的組件里調用
beforeRouteEnter
。 - 調用全局的
beforeResolve
守衛 (2.5+)。 - 導航被確認。
- 調用全局的
afterEach
鉤子。 - 觸發 DOM 更新。
- 用創建好的實例調用
beforeRouteEnter
守衛中傳給next
的回調函數。