DOM事件模型分为捕获和冒泡。一个事件发生后,会在子元素和父元素之间传播(propagation)。事件传播分为三个阶段:
在任一阶段调用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中的事件机制与原生的完全不同,时间没有绑定在原生DOM上,发出的事件也是对原生事件的包装。React内部事件系统可以分为两个阶段:事件注册和事件触发。
React组件在组件加载(mount)和更新(update)时,其中的ReactDOMComponent会对传入的事件属性进行处理(_updateDOMProperties),对相关事件进行注册和存储。
React将所有的DOM事件全部注册到document节点上,事件绑定的主要方法是listenTo
方法,事件全部调用ReactEventListener
的dispatchEvent
方法。
事件绑定以后会执行putListener
,该方法会在ReactReconcileTransaction
事务的close阶段执行,具体由EventPluginHub
来进行管理,根据事件的类型(type)和组件标识(_rootNodeID)作为key唯一标识事件并进行存储。
事件执行时,document上绑定事件ReactEventListener.dispatchEvent
会对事件进行分发,根据之前存储的类型和组件标识找到触发事件的组件。ReactEventEmitter
利用EventPluginHub
注入的plugins会将原生的DOM事件转化成合成的事件,然后批量执行存储的回调函数。
回调函数的执行分为两步:第一步是把所有的合成事件放到事件队列中,第二步是逐个执行。
原生事件阻止冒泡会阻止合成事件的触发,而合成事件的阻止冒泡不影响原生组件。所以两者最好不要混合使用,否则会出现一些奇怪的问题。
React事件机制的优点:
Copyright© 2013-2020
All Rights Reserved 京ICP备2023019179号-8