事件机制

浏览器事件机制

DOM事件模型分为捕获和冒泡。一个事件发生后,会在子元素和父元素之间传播(propagation)。事件传播分为三个阶段:

  • 捕获(Capture):事件对象从window对象传递到目标对象的过程。
  • 目标(target):目标节点在处理事件的过程。
  • 冒泡(Bubble):事件对象从目标对象传递到window对象的过程。

在任一阶段调用stopPropagation都将终止本次事件的传播。

注册事件

注册事件使用addEventListener(event, function, useCapture),第三个参数可以是布尔值,也可以是对象。是布尔值useCapture参数的情况下,默认值为false,表示注册事件是冒泡事件,为true时表示注册事件是捕获事件。

当是对象参数时,可以使用以下几个属性:

  • capture:布尔值,同useCapture
  • once:布尔值,值为true表示事件只会调用一次,调用以后移除监听
  • passive:布尔值,表示永远不会调用prevrntDedault

需要注意的是:event.target是指向引起触发事件的元素,event.currentTarget则是事件绑定的元素。

阻止冒泡和默认事件

为什么要阻止事件冒泡?这是因为某DOM节点绑定了某个事件监听器,当该DOM节点触发事件的时候才会执行回调函数,但是如果该节点的某后代节点触发了一个事件,也会由于事件冒泡导致该DOM节点的事件也被触发,在不应该的情况下执行了回调函数。

调用stopPropagation严格来说不是阻止冒泡,是阻止事件的传播,所以在捕获阶段也可以阻止。

调用stopImmediatePropagation同样能阻止事件,但是还能阻止该事件目标执行其他注册事件。

还有一种事件方式叫做preventDefault,它的作用不是用于阻止冒泡,而是阻止浏览器默认行为。如a标签跳转,表单提交等。

事件代理(事件委托)

如果一个节点中的子节点是动态生成的,那么子节点注册事件的时候应该注册在父节点上。这样避免了添加很多重复的事件监听器。

事件代理用到了两个JavaScript事件特性:事件冒泡以及目标元素。当一个元素上的事件被触发的时候,同样的事件将会在那个元素的所有祖先元素中被触发。

事件代理的处理方式有以下优点:

  • 节省内存
  • 不需要给子节点注销事件

React中的事件机制

React中的事件机制与原生的完全不同,时间没有绑定在原生DOM上,发出的事件也是对原生事件的包装。React内部事件系统可以分为两个阶段:事件注册和事件触发。

事件注册

React组件在组件加载(mount)和更新(update)时,其中的ReactDOMComponent会对传入的事件属性进行处理(_updateDOMProperties),对相关事件进行注册和存储。

React将所有的DOM事件全部注册到document节点上,事件绑定的主要方法是listenTo方法,事件全部调用ReactEventListenerdispatchEvent方法。

回调储存

事件绑定以后会执行putListener,该方法会在ReactReconcileTransaction事务的close阶段执行,具体由EventPluginHub来进行管理,根据事件的类型(type)和组件标识(_rootNodeID)作为key唯一标识事件并进行存储。

事件触发

事件执行时,document上绑定事件ReactEventListener.dispatchEvent会对事件进行分发,根据之前存储的类型和组件标识找到触发事件的组件。ReactEventEmitter利用EventPluginHub注入的plugins会将原生的DOM事件转化成合成的事件,然后批量执行存储的回调函数。

回调函数的执行分为两步:第一步是把所有的合成事件放到事件队列中,第二步是逐个执行。

常见问题

原生事件阻止冒泡会阻止合成事件的触发,而合成事件的阻止冒泡不影响原生组件。所以两者最好不要混合使用,否则会出现一些奇怪的问题。

React事件机制的优点:

  • 减少内存消耗,提升性能,一种事件类型只在document上注册一次
  • 统一规范,解决ie事件兼容问题,简化事件逻辑
  • 对开发者友好

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • JavaScript学习(二)

    数组是一个值的集合,每个值都有一个索引号,从0开始,每个索引都有一个相应的值,根据需要添加更多数值。

    Cloud-Cloudys
  • 『笔记』可扩展架构设计之消息队列

    众所周知,开发低耦合系统是软件开发的终极目标之一。低耦合的系统更加容易扩展,低耦合的模块更加容易复用,更易于维护和管理。我们知道,消息队列的主要功能就是收发消息...

    Cloud-Cloudys
  • HTTPie的使用

    Cloud-Cloudys
  • js高程之事件通识篇(一)

    在早期的浏览器厂商都认为页面中的元素事件都不仅仅是当前元素上,而是相关的其他元素甚至整个页面都应该相关的机制。但有意思的是,早期的两个开发团队分别是ie和Net...

    RobinsonZhang
  • C#系列学习笔记之事件

    需要使用winform来实现传入图片的base64值,调用接口,返回结果这样的一个功能。大致的设置如下图:

    算法发
  • javascript事件流的原理

    事件是用户或浏览器自身执行的某种动作,如click,load和mouseover都是事件的名字。

    前端老鸟
  • 微服务架构下的数据一致性保证(二)

    大家好,今天是第二次在这里给大家分享数据一致性的话题,在第一篇分享中我们介绍了微服务架构下应该满足数据最终一致性原则,并介绍实现最终一致性3种模式。 本文是...

    yuanyi928
  • Vue中鼠标事件

    乐心湖
  • 事件溯源模式

    使用只追加存储来记录对数据采取的完整系列操作,而不是仅存储域中数据的当前状态。 该存储可作为记录系统,可用于具体化域对象。 这样一来,无需同步数据模型和业务域,...

    只喝牛奶的杀手
  • 13事件

    IE8中提供的事件监听器为:element.attachEvent(eventName,functionName)

    Dreamy.TZK

扫码关注云+社区

领取腾讯云代金券