vue-router原理主要分成兩部分,一部分是安裝,另一個是實作資料監控,頁面跳轉。
安裝
export function install(Vue) {
Vue.mixin({
beforeCreate() {
// ...
this._router.init(this);
Vue.util.defineReactive(this, '_route', this._router.histroy.current)
registerInstance(this, this);
}
destoryed() {
registerInstance(this);
}
});
}
通過混入beforeCreate實作,路由的綁定和監聽操作。初始化router。調用Vue工具類方法defineReactive,當router發生改變時,頁面能及時響應更新。最後通過registerInstance來實作對
router-view
的挂載操作。
資料監控和頁面跳轉
路由更新 -> 視圖。路由發生變化(hash有hashChange監聽方法,history有popstate),改變浏覽器裡的位址,再更新視圖。采用hash或者history的路由模式,前端實作路由跳轉。history模式中,主要通過pushstate、replaceState、go實作,它們負責改變浏覽器的路由,但是不跳轉,這就實作了前端的路由,而popstate是監聽方法,處理路由改變後,前端頁面的顯示問題。就是用棧來實作。
window.addEventListener('hashChange', function() { // ... });
window.addEventListener('popstate', function() { // ... });
如何實作hash和history路由
hash
hash路由一個明顯的标志是帶有#,我們主要是通過監聽url中的hash變化來進行路由跳轉。
class Router {
constructor() {
this.currentUrl = '';
this.routers = {};
this.addEventListener('load', this.refresh, false);
this.addEventListener('hashChange', this.refresh, false);
};
router = (path, callback) => {
this.routers[path] = callback | function() {};
}
refresh = () => {
this.currentUrl = location.hash.slice[1] | '/';
// slice
// slice方法,slice(start, end), 會傳回一個新函數,而splice會修改原函數
this.routers[this.currentUrl]();
}
}
頁面代碼
<ul>
<li><a href="#/" target="_blank" rel="external nofollow" >turn white</a></li>
<li><a href="#/blue" target="_blank" rel="external nofollow" >turn blue</a></li>
<li><a href="#/green" target="_blank" rel="external nofollow" >turn green</a></li>
</ul>
window.Router = new Router();
var content = document.querySelector('body');
// change Page anything
function changeBgColor(color) {
content.style.backgroundColor = color;
}
Router.route('/', function() {
changeBgColor('white');
});
Router.route('/blue', function() {
changeBgColor('blue');
});
Router.route('/green', function() {
changeBgColor('green');
});
histoty
HTML5新路由方案,History API
常用API
window.history.back();
window.history.forward();
window.history.go(-3);
history.pushState
用于在浏覽曆史中添加曆史記錄,但是并不觸發跳轉,此方法接受三個參數,依次為:
state:一個與指定網址相關的狀态對象,popstate事件觸發時,該對象會傳入回調函數。如果不需要這個對象,此處可以填null。
title:新頁面的标題,但是所有浏覽器目前都忽略這個值,是以這裡可以填null。
url:新的網址,必須與目前頁面處在同一個域。浏覽器的位址欄将顯示這個網址。
history.replaceState
方法的參數與
pushState
方法一模一樣,差別是它修改浏覽曆史中目前紀錄,而非添加記錄,同樣不觸發跳轉。
popstate
事件,每當同一個文檔的浏覽曆史(即history對象)出現變化時,就會觸發
popstate
事件。
需要注意的是,僅僅調用
pushState
方法或
replaceState
方法 ,并不會觸發該事件,隻有使用者點選浏覽器倒退按鈕和前進按鈕,或者使用 JavaScript 調用back、forward、go方法時才會觸發。
class Router {
constructor() {
this.routers = {};
this._bindPopstate();
}
// 初始化路由
init = (path) => {
this.replaceState({path: path}, null, path);
this.routers[path] && this.routers[path]();
}
// 将路徑和對應的回調函數放到hashMap中
route = (path, callback) => {
this.routers[path] = callback || function() {};
}
// 觸發路由對應的回調
go = (path) => {
this.pushstate({path: path}, null, path);
this.routers[path] && this.routers[path]();
}
_bindPopstate = () => {
window.addEventListener('popstate', e => {
const path = e.state ? e.state.path : '';
this.routers[path] && this.routers[path]();
});
}
}
參考文章,前端路由簡介以及vue-router實作原理
寫作時間:20190214