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 版本改了