通过发布订阅模式实现的事件委托

栏目: jQuery · 发布时间: 6年前

内容简介:之前了解到的事件代理不多,就像是一个dom将事件委托给另一个dom,又叫事件委托。后来做了个题目,要实现一个类似jquery的事件委托方法,然后认真的了解了一下。然后专注于实现,其实并没有去看jquery的源码,hhh。发布订阅模式大概是目前前端框架使用的一种最常见的设计模式了,而我目前也只对发布订阅模式有一定了解,其他的设计模式待后续学习整理。在jquery中,实现事件委托只需要下面这一行代码就可以搞定

之前了解到的事件代理不多,就像是一个dom将事件委托给另一个dom,又叫事件委托。后来做了个题目,要实现一个类似jquery的事件委托方法,然后认真的了解了一下。然后专注于实现,其实并没有去看jquery的源码,hhh。

发布订阅模式大概是目前前端框架使用的一种最常见的 设计模式 了,而我目前也只对发布订阅模式有一定了解,其他的设计模式待后续学习整理。

关于事件委托实现

在jquery中,实现事件委托只需要下面这一行代码就可以搞定

$("#container").on('click', 'item', fn)
复制代码

之前会觉得这么用理所当然,所以并没有想到哪一天我会亲手去实现一个这样的功能,现在机会来了。

题目给的很简单,就是将子节点的事件绑到其父节点上,比如下面这段dom,就是将 <li> 的事件绑定到 <ul> 上,实现点击 <li> 时触发 <ul> 上的事件。

<div  id="container">
    <li class="item" id="item1">
        <span id="btn1">hello</span>
    </li>
    <li class="item">
        <span>world</span>
    </li>
</div>
复制代码

题目的js部分是这样的

!function(root, doc){
    class Delegator {
        constructor (selector/* root选择器 */) {
        // TODO
        }

        on (event/* 绑定事件 */, selector/* 触发事件节点对应选择器 */, fn/* 触发函数 */) {
          // TODO
        }

        destroy () {
        // TODO
        }
    }
}(window,document)
复制代码

然后实现一个功能类似上面jquery的事件委托,就像下面这样的

var delegator = new Delegator('#container');
delegator.on('click', 'li.item', fnli)
复制代码

忘记一开始想的是什么方法了,反正写到一半的时候突然想起了订阅发布模式(因为刚好那几天在看发布订阅模式),然后开始撸代码。

分解上面的方法,其实可以看作是一个监听器

delegator.addEventListener('click', delegatorFn)
复制代码

只不过这个 delegatorFn 有点特殊,它需要遍历这个所有委托‘click’事件给 delegator 的子节点,并执行他们的委托 fnli

首先,我们把所有的委托当作是一个订阅事件,只不过这个事件里包含了委托者。在 Delegator 对象的原型里增加一个属性 eventObj ,里面存放订阅‘click’事件的所有的委托者和委托事件,结构差不多是这样的

this.eventObj.click=[{
    selecter:'li.item',
    callback:fnli
}]
复制代码

那么整个on的方法其实就是委托者 selector 订阅事件并委托给调on的被委托者

on (event/* 绑定事件 */, selector/* 触发事件节点对应选择器 */, fn/* 触发函数 */) {
      // TODO
    
      if(!this.eventsObj[event]){
        this.eventsObj[event] = [];
      }
      this.eventsObj[event].push({
          selector,
          callback: fn
      })
      //这里委托事件给this.root,当被委托者坚挺到event事件时,会触发委托函数delegatorFn
      this.root.addEventListener(event, delegatorFn);
      //因为on可以链式调用,所以这里需要返回
      return this;
    }
复制代码

现在需要实现 delegatorFn 方法了,其实也很简单,主要是遍历事件经过的所有dom中哪个 selector 订阅了它,它就执行对应节点携带的 fn

delegatorFn = (e) => {
    let target = e.target;//触发事件的selector
    let currentTarget = e.currentTarget; //被委托者
        //判断触发事件的节点及它冒泡经过的节点是否是被委托者,若是,则表示不再有委托者,无需遍历
    while(target !== currentTarget){
        this.eventsObj[e.type].forEach(item => {
            //查找订阅事件者
            if(target.matches(item.selector)){
                //执行订阅事件者携带的函数
                item.callback.call(target,e);
            }
        });
        //往上冒泡
        target = target.parentNode;
    }
}
复制代码

以上,就是通过发布订阅实现的事件委托的核心部分,主要涉及的还有事件的冒泡。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

平台转型

平台转型

陈威如、王诗一、余卓轩(统筹) / 中信出版社 / 2016-1-10 / 58

《平台战略》续篇,陈威如等关于企业平台转型最新力作! 平台带来的商业革命已改写了现在及未来的企业生存规则,而这股浪潮已经从互联网行业漫延到了其他多种行业之中!如果说,过去10 年是平台商业模式在互联网行业的爆发期,那未来10 年,将是平台商业模式在传统行业转型应用上的黄金时代。 平台思维不再是互联网行业的专用词,它可以用来解构价值链,可以被运用到组织架构的设计中,更能够帮助企业升级竞争......一起来看看 《平台转型》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

SHA 加密
SHA 加密

SHA 加密工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具