Skip to content

04.注册监听事件

packages/react-dom-bindings/src/events/DOMPluginEventSystem.js

diff
import { allNativeEvents } from './EventRegistry';
import * as SimpleEventPlugin from './plugins/SimpleEventPlugin';

+import { IS_CAPTURE_PHASE } from './EventSystemFlags';
+import { createEventListenerWrapperWithPriority } from './ReactDOMEventListener';
+import {
+  addEventCaptureListener,
+  addEventBubbleListener
+} from './EventListener';

SimpleEventPlugin.registerEvents();
const listeningMarker = `_reactListening` + Math.random().toString(36).slice(2);

+/**
+ * 监听所有支持的事件
+ * @param {Element} rootContainerElement 根容器元素
+ */
export function listenToAllSupportedEvents(rootContainerElement) {
+  // 如果此元素尚未标记为已监听,则监听所有原生事件
+  if (!rootContainerElement[listeningMarker]) {
+    rootContainerElement[listeningMarker] = true;
+    allNativeEvents.forEach((domEventName) => {
+      listenToNativeEvent(domEventName, true, rootContainerElement);
+      listenToNativeEvent(domEventName, false, rootContainerElement);
+    });
+  }
}

+/**
+ * 监听原生事件
+ * @param {string} domEventName DOM 事件名称
+ * @param {boolean} isCapturePhaseListener 是否在捕获阶段监听
+ * @param {Element} target 目标元素
+ */
+export function listenToNativeEvent(domEventName, isCapturePhaseListener, target) {
+  let eventSystemFlags = 0;
+  // 如果在捕获阶段监听,设置事件系统标记
+  if (isCapturePhaseListener) {
+    eventSystemFlags |= IS_CAPTURE_PHASE;
+  }
+  addTrappedEventListener(target, domEventName, eventSystemFlags, isCapturePhaseListener);
+}

+/**
+ * 添加受限制的事件监听器
+ * @param {Element} targetContainer 目标容器元素
+ * @param {string} domEventName DOM 事件名称
+ * @param {number} eventSystemFlags 事件系统标记
+ * @param {boolean} isCapturePhaseListener 是否在捕获阶段监听
+ */
+function addTrappedEventListener(
+  targetContainer, domEventName, eventSystemFlags, isCapturePhaseListener
+) {
+  // 创建带有优先级的事件监听器
+  const listener = createEventListenerWrapperWithPriority(targetContainer, domEventName, eventSystemFlags);
+  // 根据监听阶段选择合适的添加监听函数
+  if (isCapturePhaseListener) {
+    addEventCaptureListener(targetContainer, domEventName, listener);
+  } else {
+    addEventBubbleListener(targetContainer, domEventName, listener);
+  }
+}

packages/react-dom-bindings/src/events/EventListener.js

js
/**
 * 在目标元素上添加捕获阶段的事件监听器
 * 
 * @param {EventTarget} target - 目标元素,我们想要在上面添加监听器的元素
 * @param {string} eventType - 事件类型,我们想要监听的事件的名称
 * @param {Function} listener - 监听器函数,当事件发生时将调用的函数
 * 
 * @returns {Function} 返回添加的监听器函数
 */
export function addEventCaptureListener(target, eventType, listener) {
  // 调用目标元素的 addEventListener 方法,添加捕获阶段的事件监听器
  target.addEventListener(eventType, listener, true);
  
  // 返回添加的监听器函数
  return listener;
}

/**
 * 在目标元素上添加冒泡阶段的事件监听器
 * 
 * @param {EventTarget} target - 目标元素,我们想要在上面添加监听器的元素
 * @param {string} eventType - 事件类型,我们想要监听的事件的名称
 * @param {Function} listener - 监听器函数,当事件发生时将调用的函数
 * 
 * @returns {Function} 返回添加的监听器函数
 */
export function addEventBubbleListener(target, eventType, listener) {
  // 调用目标元素的 addEventListener 方法,添加冒泡阶段的事件监听器
  target.addEventListener(eventType, listener, false);
  
  // 返回添加的监听器函数
  return listener;
}

packages/react-dom-bindings/src/events/ReactDOMEventListener.js

js
/**
 * 创建一个具有优先级的事件监听器包装器。
 *
 * @param {HTMLElement} targetContainer - 目标容器,通常是一个HTML元素。
 * @param {string} domEventName - DOM事件名称。
 * @param {number} eventSystemFlags - 事件系统标志,用于表示事件在哪个阶段(冒泡/捕获)。
 * @returns {function} - 绑定了特定参数的事件调度函数。
 */
export function createEventListenerWrapperWithPriority(
  targetContainer,
  domEventName,
  eventSystemFlags
) {
  const listenerWrapper = dispatchDiscreteEvent;
  return listenerWrapper.bind(null, domEventName, eventSystemFlags, targetContainer);
}

/**
 * 调度离散事件。
 *
 * @param {string} domEventName - DOM事件名称。
 * @param {number} eventSystemFlags - 事件系统标志,用于表示事件在哪个阶段(冒泡/捕获)。
 * @param {HTMLElement} container - 目标容器,通常是一个HTML元素。
 * @param {Event} nativeEvent - 原生的浏览器事件对象。
 */
function dispatchDiscreteEvent(domEventName, eventSystemFlags, container, nativeEvent) {
}

基于 VitePress 构建