天天看點

vue addeventlistener_vue-router原理

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