React合成事件有哪些基础知识,原理是什么
Admin 2022-08-12 群英技术资讯 257 次浏览
事件是在编程时系统内发生的动作或者发生的事情,而开发者可以某种方式对事件做出回应,而这里有几个先决条件
在机场等待检票,听到广播后排队检票
// 检票事件 var event = new Event('check-ticket'); // 事件注册,并编写回调 elem.addEventListener('check-ticket', function (e) { // 开始排队 LiningUp() }); // 事件触发,广播开始检票 elem.dispatchEvent(event);
不是浏览器本身触发的事件,自己创建和触发的事件。
// HTML中的写法 <button onclick="handleClick()"> Activate Lasers </button> // React中的写法 <button onClick={handleClick}> Activate Lasers </button>
提供了一种“顶层注册,事件收集,统一触发”的事件机制
时机:在fiber
节点进入render
阶段的complete
阶段时,名为onClick的props会被识别为事件进行处理
function setInitialDOMProperties( tag: string, domElement: Element, rootContainerElement: Element | Document, nextProps: Object, isCustomComponentTag: boolean, ): void { for (const propKey in nextProps) { if (!nextProps.hasOwnProperty(propKey)) { ... } else if (registrationNameDependencies.hasOwnProperty(propKey)) { // 如果propKey属于事件类型,则进行事件绑定 ensureListeningTo(rootContainerElement, propKey, domElement); } } } } // registrationNameDependencies为合成事件名和真实事件的映射,格式如下: { onChange: ['change', 'click', 'focusin', 'focusout', 'input', 'keydown', 'keyup', 'selectionchange'] onChangeCapture: ['change', 'click', 'focusin', 'focusout', 'input', 'keydown', 'keyup', 'selectionchange'] onClick: ['click'] }
调用ensureListeningTo
进行事件绑定
然后调用DOMPluginEventSystem.js中的addTrappedEventListener
进行事件注册,而监听器listener是React通过createEventListenerWrapperWithPriority
创建出优先级不同的时间监听包装器
总的来说,会有三种事件监听包装器:
负责以不同的优先级权重来触发真正的事件流程
在createEventListenerWrapperWithPriority
中,根据eventPriority
事件优先级不同调用事件dispatchDiscreteEvent
、dispatchUserBlockingUpdate
、dispatchUserBlockingUpdate
、dispatchEvent
进行事件绑定
export function createEventListenerWrapperWithPriority( targetContainer: EventTarget, domEventName: DOMEventName, eventSystemFlags: EventSystemFlags, ): Function { const eventPriority = getEventPriorityForPluginSystem(domEventName); let listenerWrapper; switch (eventPriority) { case DiscreteEvent: listenerWrapper = dispatchDiscreteEvent; break; case UserBlockingEvent: listenerWrapper = dispatchUserBlockingUpdate; break; case ContinuousEvent: default: listenerWrapper = dispatchEvent; break; } return listenerWrapper.bind( null, domEventName, eventSystemFlags, targetContainer, ); }
在每一个事件绑定函数中,会调用dispatchEventsForPlugins
函数
合成事件,放入dispatchQueue中
而dispatchQueue由两部分组成
执行事件执行路径下的事件,从dispatchQueue
中取出事件对象events
和具体执行路径listeners
,然后遍历执行
function dispatchEventsForPlugins( domEventName: DOMEventName, eventSystemFlags: EventSystemFlags, nativeEvent: AnyNativeEvent, targetInst: null | Fiber, targetContainer: EventTarget, ): void { const nativeEventTarget = getEventTarget(nativeEvent); const dispatchQueue: DispatchQueue = []; // 通过不同事件类型插件进行事件对象合成,将合成事件放入事件队列中:dispatchQueue中 extractEvents( dispatchQueue, domEventName, targetInst, nativeEvent, nativeEventTarget, eventSystemFlags, targetContainer, ); // 执行dispatchQueue中具体事件执行路径下的事件 processDispatchQueue(dispatchQueue, eventSystemFlags); }
// 通过extractEvents合成的dispatchQueue的格式如下 [ { // event是合成事件对象 event, // 具体的事件执行路径,currentTarget、listener等信息 listeners: [ { currentTarget: div.counter, instance: FiberNode {tag: 5, key: null, elementType: 'div', type: 'div', stateNode: div.counter, …}, listener: e => {…} }, { currentTarget: div.counter-parent, instance: FiberNode {tag: 5, key: null, elementType: 'div', type: 'div', stateNode: div.counter, …}, listener: e => {…} } ] } ]
原理:收集的事件放在dispatchQueue
数组中,而冒泡和捕获的区别在于执行时机和顺序,那么我们只需要对数组按照不同顺序循环执行即可
function processDispatchQueueItemsInOrder( event: ReactSyntheticEvent, dispatchListeners: Array<DispatchListener>, inCapturePhase: boolean, ): void { let previousInstance; if (inCapturePhase) { // 事件捕获倒序循环 for (let i = dispatchListeners.length - 1; i >= 0; i--) { const {instance, currentTarget, listener} = dispatchListeners[i]; if (instance !== previousInstance && event.isPropagationStopped()) { return; } // 执行事件,传入event对象,和currentTarget executeDispatch(event, listener, currentTarget); previousInstance = instance; } } else { // 事件冒泡正序循环 for (let i = 0; i < dispatchListeners.length; i++) { const {instance, currentTarget, listener} = dispatchListeners[i]; // 如果事件对象阻止了冒泡,则return掉循环过程 if (instance !== previousInstance && event.isPropagationStopped()) { return; } executeDispatch(event, listener, currentTarget); previousInstance = instance; } } }
以上就是最近学习React源码之--合成事件的知识整理啦!
首先会在fiber
节点进入render
阶段的complete
阶段时,将事件监听绑定在root上。然后调用ensureListeningTo
进行事件绑定,生成事件合成对象、收集事件、触发真正的事件。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。
猜你喜欢
这篇文章给大家分享的是微信小程序中多图片上传效果的实现。小编觉得挺实用的,因此分享给大家做个参考,文中示例代码介绍的非常详细,感兴趣的朋友接下来一起跟随小编看看吧。
这篇文章主要给大家分享jquery实现记分进度条效果的内容,感兴趣的朋友可以借鉴参考一下,希望大家阅读完这篇文章能有所收获,下面我们一起来学习一下吧。
varfs=require("fs");varpath=require("path");//递归创建目录异步方法functionmkdirs(dirname,callback){fs.exists(dirname,function(exists){if(exists){call
这篇文章主要介绍如何用JS写一个发布订阅模式,什么是发布订阅模式?能手写实现一下吗?它和观察者模式有区别吗?带着疑惑一起解开下面文章的内容吧
这篇文章主要为大家详细介绍了jQuery呼吸轮播图制作原理,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
成为群英会员,开启智能安全云计算之旅
立即注册Copyright © QY Network Company Ltd. All Rights Reserved. 2003-2020 群英 版权所有
增值电信经营许可证 : B1.B2-20140078 粤ICP备09006778号 域名注册商资质 粤 D3.1-20240008