最近想寫個簡單blog來練習下vue全家桶,其中特別想實現相似github的頁面加載行爲。vue
翻了下api,vue-router提供導航鉤子給開發者實現導航攔截git
router.beforeEach((to, from, next) => { })
但實驗後發現,當鉤子執行的時候url/hash的狀態已經改變並且難以實現進度條。github
翻查源代碼後發現更改url主要是在history實例中進行,其中history暴露一個listen的方法來監聽路由的改變從而更新vue的root元素的路由值。vue-router
history.listen(route => { this.app._route = route })
在這裏只要延遲_route的賦值就能延遲UI和url的更新,甚至能替換路由api
最終代碼,這裏沒有用做進度條,配合store能夠實現相似github的進度條指示器,以及超時處理app
// 定義一個正在加載的Route的訪問器 Object.defineProperty(Vue.prototype, '$routePending', { get () { return this.$root._routePending; } }); //hook vm建立 Vue.mixin({ /** * hook route updated */ beforeCreate () { if (this.$options.router) { //定義一個響應式屬性 Vue.util.defineReactive(this, '_routePending', null); //延遲賦值並作預加載 this._router.history.listen(route => { this._routePending = route; Promise.resolve() .then(() => { //過濾非執行中的route if (route != this._routePending) { return; } if (route.matched) { //路由有匹配的組件 let reduce = route.matched.reduce((list, item) => { Object.keys(item.components).forEach(k => { let component = item.components[k]; if (component.preFetch) { list.push(component.preFetch); //全部組件的preFetch入列 } }); return list; }, []); if (reduce.length > 0) { return Promise.all(reduce.map(fn => fn(route))); } return route; } }) .then(() => { //過濾非執行中的route if (route != this._routePending) { return; } // this._route = route; this._routePending = null; }) .catch(e => { console.warn(e); this._router.replace('/500'); }); }); } } });
已知問題:this
原來的導航鉤子可能出現問題url
PS:文中極可能出現錯誤,這裏給出一個思路prototype