JavaScript如何实现history路由变化监听

前言

你们都知道,经过浏览器的地址栏来改变切换页面,前端实现主要有两种方式:javascript

①经过hash改变,利用window.onhashchange 监听。前端

②经过history的改变,进行js操做加载页面,然而history并不像hash那样简单,由于history的改变,除了浏览器的几个前进后退(使用 history.back(), history.forward()和 history.go() 方法来完成在用户历史记录中向后和向前的跳转。)等操做会主动触发popstate 事件,pushState,replaceState 并不会触发popstate事件,本篇文章主要解决history监听的问题,下面来看下具体实现java

思路

咱们首先完成一个订阅-发布模式,而后重写history.pushState, history.replaceState,并添加消息通知,这样一来只要history的没法实现监听函数就被咱们加上了事件通知,只不过这里用的不是浏览器原生事件,而是经过咱们建立的event-bus 来实现通知,而后触发事件订阅函数的执行。 废话很少说,下面咱们来作具体操做。浏览器

订阅-发布模式示例

class Dep {                  // 订阅池
    constructor(name){
        this.id = new Date() //这里简单的运用时间戳作订阅池的ID
        this.subs = []       //该事件下被订阅对象的集合
    }
    defined(){              // 添加订阅者
        Dep.watch.add(this);
    }
    notify() {              //通知订阅者有变化
        this.subs.forEach((e, i) => {
            if(typeof e.update === 'function'){
                try {
                   e.update.apply(e)  //触发订阅者更新函数
                } catch(err){
                    console.warr(err)
                }
            }
        })
    }
    
}
Dep.watch = null;

class Watch {
    constructor(name, fn){
        this.name = name;       //订阅消息的名称
        this.id = new Date();   //这里简单的运用时间戳作订阅者的ID
        this.callBack = fn;     //订阅消息发送改变时->订阅者执行的回调函数 
    }
    add(dep) {                  //将订阅者放入dep订阅池
       dep.subs.push(this);
    }
    update() {                  //将订阅者更新方法
        var cb = this.callBack; //赋值为了避免改变函数内调用的this
        cb(this.name);          
    }
}
复制代码

重写history方法,并添加window.addHistoryListener事件机制。

下面咱们只须要对history的方法进行重写,并添加event-bus便可,代码以下:app

var addHistoryMethod = (function(){
        var historyDep = new Dep();
        return function(name) {
            if(name === 'historychange'){
                return function(name, fn){
                    var event = new Watch(name, fn)
                    Dep.watch = event;
                    historyDep.defined();
                    Dep.watch = null;       //置空供下一个订阅者使用
                }
            } else if(name === 'pushState' || name === 'replaceState') {
                var method = history[name];
                return function(){
                    method.apply(history, arguments);
                    historyDep.notify();
                }
            }
            
        }
}())

window.addHistoryListener = addHistoryMethod('historychange');
history.pushState =  addHistoryMethod('pushState');
history.replaceState =  addHistoryMethod('replaceState');

复制代码

测试History事件监听

上面咱们给window添加了一个addHistoryListener事件监听,相似于 addEventListener的方法,而后咱们有作了history的pushState, replaceState的改写,接下来咱们测试一下。函数

window.addHistoryListener('history',function(){
    console.log('窗口的history改变了');
})
window.addHistoryListener('history',function(){
    console.log('窗口的history改变了-我也听到了');
})
history.pushState({first:'first'}, "page2", "/first")
复制代码

观察上面结果打印;咱们发现window的 history改变,咱们成功的添加了事件监听!固然这里仍是有缺陷的,就是少了事件的移除,有兴趣的同窗能够把接下来的移除也书写一下,熟悉熟悉。测试

相关文章
相关标签/搜索