1.$router和$route區別
router為VueRouter的實例,相當於一個全局的路由器對象,里面含有很多屬性和子對象,例如history對象,和router-link跳轉一樣,this.$router.push會往history棧中添加一個新的記錄。
route相當於當前正在跳轉的路由對象,可以從里面獲取name,path,params,query等。
2.vue路由實現原理
通過改變 URL,在不重新請求頁面的情況下,更新頁面視圖。
Location對象的屬性
Location對象的方法
H5中的History對象的屬性(部分)
H5中的History對象的方法(部分)
其中pushState
方法和replaceState
方法可以分別增加和替換掉一條記錄(必須同源),而不會重新加載頁面。window.location.hash和window.history.pushState(或replaceState)唯一的不同是通過hash改變url帶入#,而后者不會。而Vue 路由的兩種模式就是基於location和history這2個對象的!
ps:注意這里可以通過重寫pushstate和replacestate實現對history模式路由的監聽
最后說下兩者的應用場景,如果hash模式F5刷新是不會向服務端請求#后面的url的,而history模式會,如果服務端沒做處理,很容易出現404!
3.vue路由導航鈎子
1.全局導航鈎子
主要有兩種鈎子:前置守衛、后置鈎子
注冊一個全局前置守衛:
const router = new VueRouter({ ... }); router.beforeEach((to, from, next) => { // do someting });
這三個參數 to 、from 、next 分別的作用:
to: Route,代表要進入的目標,它是一個路由對象
from: Route,代表當前正要離開的路由,同樣也是一個路由對象
next: Function,這是一個必須需要調用的方法,而具體的執行效果則依賴 next 方法調用的參數
next():進入管道中的下一個鈎子,如果全部的鈎子執行完了,則導航的狀態就是 confirmed(確認的)
next(false):這代表中斷掉當前的導航,即 to 代表的路由對象不會進入,被中斷,此時該表 URL 地址會被重置到 from 路由對應的地址
next(‘/’) 和 next({path: ‘/’}):在中斷掉當前導航的同時,跳轉到一個不同的地址
next(error):如果傳入參數是一個 Error 實例,那么導航被終止的同時會將錯誤傳遞給 router.onError() 注冊過的回調
全局后置鈎子:
router.afterEach((to, from) => { // do someting });
不同於前置守衛,后置鈎子並沒有 next 函數,也不會改變導航本身
2. 路由獨享的鈎子
單個路由獨享的導航鈎子,它是在路由配置上直接進行定義的:
cont router = new VueRouter({ routes: [ { path: '/file', component: File, beforeEnter: (to, from ,next) => { // do someting } } ] });
3.組件內的導航鈎子
組件內的導航鈎子主要有這三種:beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave。他們是直接在路由組件內部直接進行定義的:
const File = { template: `<div>This is file</div>`, beforeRouteEnter(to, from, next) { // do someting // 在渲染該組件的對應路由被 confirm 前調用 }, beforeRouteUpdate(to, from, next) { // do someting // 在當前路由改變,但是依然渲染該組件是調用 }, beforeRouteLeave(to, from ,next) { // do someting // 導航離開該組件的對應路由時被調用 } }
beforeRouteEnter 不能獲取組件實例 this,因為當守衛執行前,組件實例被沒有被創建出來,剩下兩個鈎子則可以正常獲取組件實例 this
可以通過給 next 傳入一個回調來訪問組件實例。在導航被確認是,會執行這個回調,這時就可以訪問組件實例了
beforeRouteEnter(to, from, next) { next (vm => { // 這里通過 vm 來訪問組件實例解決了沒有 this 的問題 }) }
僅僅是 beforRouteEnter 支持給 next 傳遞回調,其他兩個並不支持。因為歸根結底,支持回調是為了解決 this 問題,而其他兩個鈎子的 this 可以正確訪問到組件實例,所有沒有必要使用回調、
4.完整的導航解析流程
1.導航被觸發
2.在失活的組件里調用離開守衛
3.調用全局的 beforeEach 守衛
4.在重用的組件里調用 beforeRouteUpdate 守衛
5.在路由配置里調用 beforEnter
6.解析異步路由組件
7.在被激活的組件里調用 beforeRouteEnter
8.調用全局的 beforeResolve 守衛
9.導航被確認
10.調用全局的 afterEach 鈎子
11.觸發 DOM 更新
12.在創建好的實例調用 beforeRouteEnter 守衛中傳給 next 的回調函數
4.vue-router中的hash模式、history模式、abstract模式
1.哈希模式(hash mode)
這是開發中的默認模式,在url中永遠帶着#號,在瀏覽器方面其支持度極佳,甚至兼容低版本的ie瀏覽器。
即#是用來指導瀏覽器動作的,對服務器端完全無用,HTTP請求中,不包含#。
每一次改變#后的部分,都會在瀏覽器的訪問歷史中增加一個記錄,使用”后退”按鈕,就可以回到上一個位置。
前端路由的原理:window是可以監聽到哈希值的變化的(onhashchage事件),這就意味着:當url中的哈希值發生了變化,無需發起http請求,window也可以監聽到這種變化,並按需加載前端的代碼塊。
哈希模式也是當下單頁面應用的標配,所謂前端路由的強大之處也就在這里:路由分發不需要服務器來做,前端自己就可以完成。
2.歷史模式(history mode)
在url中不帶#號,用的是傳統的路由分發模式,即當用戶輸入一個url時,是由服務器在接受用戶的這個輸入請求,並由服務器解析url的路徑然后做相應邏輯處理。
如果要做到改變url但又不刷新頁面的潮流效果,就需要前端用上pushState和replaceState兩個H5的api,來把url替換的同時又不刷新頁面,但需要后端人員去配置url重定向的問題,不然在訪問二級頁面時,做刷新操作會報404的錯誤。這和哈希天生就不會刷新頁面的特性不同,歷史模式來做這件事屬於一種“障眼法”,或者說是“老技術干新活”,又廢又麻煩。
hash模式下:xxx.com/#/id=5 請求地址為 xxx.com,沒有問題。
history模式下:xxx.com/id=5 請求地址為 xxx.com/id=5,如果后端沒有對應的路由處理,就會返回404錯誤
需要后台配置支持:
在服務端增加一個覆蓋所有情況的候選資源:如果 URL 匹配不到任何靜態資源,則應該返回同一個 index.html 頁面,這個頁面就是你 app 依賴的頁面。
3.abstract模式
abstract模式是使用一個不依賴於瀏覽器的瀏覽歷史虛擬管理后端。
根據平台差異可以看出,在 Weex 環境中只支持使用 abstract 模式。 不過,vue-router 自身會對環境做校驗,如果發現沒有瀏覽器的 API,vue-router 會自動強制進入 abstract 模式,所以 在使用 vue-router 時只要不寫 mode 配置即可,默認會在瀏覽器環境中使用 hash 模式,在移動端原生環境中使用 abstract 模式。