最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • JS实现监听路由变化

    正文概述 掘金(Hecate)   2021-02-26   2188

    JS实现监听路由变化

    前言

    开始前可以温习一下,前端路由的概念:你所理解都前端路由是什么?

    我们知道前端路由实现方式有两种:

    • 哈希模式
      • 监听 onhashchange
    • 历史模式
      • history模式依赖都是原生事件popstate
      • history.pushState() 或 history.replaceState() 不会触发popstate事件

    既然要监听到所有类型页面的路由变化, 只用事件监听 hashchange 和popstate是无法满足需求的,所以需要对history对象的pushState和replaceState方法进行重写。

    实现思路

    • 完成一个订阅-发布模式
    • 重写history.pushState,history.replaceState
    • 添加消息通知(创建event-bus来实现通知)
    • 触发事件订阅函数执行

    订阅-发布模式Demo

    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即可,代码如下:

    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.addEventListener('history',function(){
        console.log('窗口的history改变了')
        console.log('当前页面链接是:',window.location.href);
    })
    
    history.pushState({first:'first'},"page2","/first");
    

    观察上面结果打印;我们发现window的 history改变,我们成功的添加了事件监听! 文章里也说了,目前这种实现方式还是有缺陷的, 就是少了事件的移除。后续测试针对多页面应用这种,此法方法有所局限, 还需要做进一步的兼容。

    参考延伸阅读

    前端路由

    如何监听路由变化?SPA实现原理及DEMO

    设计模式:订阅-发布者模式


    起源地下载网 » JS实现监听路由变化

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元