一文说明开发者如何在React中创建和触发合成事件
Admin 2023-04-10 群英技术资讯 1141 次浏览
这篇文章主要介绍了“一文说明开发者如何在React中创建和触发合成事件”相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇一文说明开发者如何在React中创建和触发合成事件文章都会有所收获,下面我们一起来看看吧。事件是在编程时系统内发生的动作或者发生的事情,而开发者可以某种方式对事件做出回应,而这里有几个先决条件
举个例子
在机场等待检票,听到广播后排队检票
// 检票事件
var event = new Event('check-ticket');
// 事件注册,并编写回调
elem.addEventListener('check-ticket', function (e) {
// 开始排队
LiningUp()
});
// 事件触发,广播开始检票
elem.dispatchEvent(event);
不是浏览器本身触发的事件,自己创建和触发的事件。
在React中事件的写法和原生事件写法的区别?
// 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中创建和触发合成事件”的学习就结束了,希望能够解决大家的疑惑,另外大家动手实践也很重要,对大家加深理解和学习很有帮助。如果想要学习更多的相关知识,欢迎关注群英网络,小编每天都会给大家分享实用的文章!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。
猜你喜欢
这篇文章主要介绍怎样用vue实现拖拽树状图,下文有实例有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章能有所收获,接下来小编带着大家一起了解看看。
这篇文章主要介绍了前端的状态管理,续上篇文章内容,今天将从 Redux 入手逐渐拓展,需要的小伙伴可以参考一下哟
这篇文章我们来了解jQuery怎样删除子元素的相关内容,在删除子元素之前,首先我们需要先获取子元素,这里需要使用children()方法来获取子元素对象,然后再用remove()方法就能删除子元素了,文中的示例代码介绍得很详细,有需要的朋友可以参考,接下来就跟随小编一起了解看看吧。
这篇文章主要介绍了vue自定义keepalive组件的相关资料,keep-alive组件是使用 include exclude这两个属性传入组件名称来确认哪些可以被缓存的,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
teleport 传送门组件,提供一种简洁的方式,可以指定它里面的内容的父元素,也就是说teleport 中的内容允许我们控制在任意的DOM中,使用简单,对VUE 3 teleport传送门相关知识感兴趣的朋友一起看看吧
成为群英会员,开启智能安全云计算之旅
立即注册关注或联系群英网络
7x24小时售前:400-678-4567
7x24小时售后:0668-2555666
24小时QQ客服
群英微信公众号
CNNIC域名投诉举报处理平台
服务电话:010-58813000
服务邮箱:service@cnnic.cn
投诉与建议:0668-2555555
Copyright © QY Network Company Ltd. All Rights Reserved. 2003-2020 群英 版权所有
增值电信经营许可证 : B1.B2-20140078 ICP核准(ICP备案)粤ICP备09006778号 域名注册商资质 粤 D3.1-20240008