react focus 事件

Tinypan發表於2024-05-27

react focus 事件

react 官網中說:“在 React 中所有事件都會傳播,除了 onScroll,它僅適用於你附加到的 JSX 標籤。”

https://react.docschina.org/learn/responding-to-events#event-propagation

那 focus 事件呢,原生 focus 事件可是非冒泡的

function MyInput() {
  function handleFocus(e) {
    console.log('focus', e);
  }
  return <input type="text" onFocus={handleFocus} />;
}

SyntheticBaseEvent 事件物件

const e = {
  bubbles: true,
  eventPhase: 3,
  type: 'focus',
  target: input,
  nativeEvent: {
    bubbles: true,
    type: 'focusin',
  },
};

從事件物件中可以看到,外層是 react 的自己的合成事件,原生事件在 nativeEvent 上,且監聽的是 focusin 事件,focusin 事件是冒泡的。

瞅一眼原始碼:

const simpleEventPluginEvents = [事件陣列];
export function registerSimpleEvents() {
  for (let i = 0; i < simpleEventPluginEvents.length; i++) {
    const eventName = ((simpleEventPluginEvents[i]: any): string);
    const domEventName = ((eventName.toLowerCase(): any): DOMEventName);
    const capitalizedEvent = eventName[0].toUpperCase() + eventName.slice(1);
    registerSimpleEvent(domEventName, 'on' + capitalizedEvent);
  }
  // Special cases where event names don't match.
  registerSimpleEvent(ANIMATION_END, 'onAnimationEnd');
  registerSimpleEvent(ANIMATION_ITERATION, 'onAnimationIteration');
  registerSimpleEvent(ANIMATION_START, 'onAnimationStart');
  registerSimpleEvent('dblclick', 'onDoubleClick');
  registerSimpleEvent('focusin', 'onFocus');
  registerSimpleEvent('focusout', 'onBlur');

  registerSimpleEvent(TRANSITION_RUN, 'onTransitionRun');
  registerSimpleEvent(TRANSITION_START, 'onTransitionStart');
  registerSimpleEvent(TRANSITION_CANCEL, 'onTransitionCancel');
  registerSimpleEvent(TRANSITION_END, 'onTransitionEnd');
}

所以在 input 標籤上繫結 onFocus 屬性時,內部監聽的其實是 focusin 事件。
如果想在 react 上監聽原生 focus 事件的話,是無法實現的。因為 simpleEventPluginEvents 陣列中並未列出 focus。要不自己寫原生程式碼監聽 focus 吧。
react 如此設計的初衷是所有的事件都委託在根節點上,聚焦事件需要冒泡給根節點處理

網上說是委託在 document 上,但我並未發現

也許是 react 18 版本改了

相關文章