如何在React应用程序中的所有onclick
处理程序之前运行代码,而不必向每个处理程序添加代码?具体来说,我想全局确保所有React onclick
处理程序都忽略中键单击。目标是解决12-year-old WebKit bug的问题,其中Safari在按下鼠标中键时会发出click
事件,而不是W3C标准的auxclick
事件(由Chrome和Firefox发出)auxclick
事件。
由于一些用户在用鼠标滚轮滚动时意外触发了中键单击,因此我想全局地忽略这些意外单击。怎么样?
我要注入的代码非常简单:
mandated
但是我不确定在哪里注入它,以便它在我应用程序中的所有事件处理程序之前运行。
一个潜在的麻烦是,我不想完全忽略中间点击(因为浏览器的默认行为是,在if (e.button !== 0) {
e.stopPropagation();
}
元素上中间点击会在新标签中打开链接)。相反,我只是想防止对那些无效的<a>
事件做出任何反应。
为了解决这个问题,我认为我必须做一些棘手的事情,例如猴子补丁React,但事实证明,这可能是一种非精确的解决方案:只需将整个应用程序包装在一个顶层组件中,即可使用click
事件,而不是普通的onClickCapture
事件。这是我为此目的编写的一个简单组件。
onClickCapture
如果您不使用TypeScript,这是该组件的普通JS版本:
click
import React, { useCallback, MouseEventHandler, ReactNode } from 'react';
export default function IgnoreSafariMiddleClicks({ children }: { children: ReactNode }) {
const onClick = useCallback<MouseEventHandler>(e => {
if (e.button !== 0) {
// Prevent middle clicks from being handled by click handlers on Safari
// browsers, in order to work around this 12-year-old WebKit bug:
// https://bugs.webkit.org/show_bug.cgi?id=22382
e.stopPropagation();
}
}, []);
return <div onClickCapture={onClick}>{children}</div>;
}
我发现的一个陷阱是import React from 'react';
export default function IgnoreSafariMiddleClicks({ children }) {
const onClick = useCallback(e => {
if (e.button !== 0) {
// Prevent middle clicks from being handled by click handlers on Safari
// browsers, in order to work around this 12-year-old WebKit bug:
// https://bugs.webkit.org/show_bug.cgi?id=22382
e.stopPropagation();
}
}, []);
return <div onClickCapture={onClick}>{children}</div>;
}
在这种情况下不起作用,因为其他React事件处理程序继续被称为aterwards。我必须使用import React from 'react';
import IgnoreSafariMiddleClicks from './IgnoreSafariMiddleClicks';
export default function App() {
return (
<IgnoreSafariMiddleClicks>
<div>
<button onClick={() => console.log('Left clicked!')}>
click me!
</button>
</div>
</IgnoreSafariMiddleClicks>
);
}
的SyntheticEvent.nativeEvent.stopImmediatePropagation
方法。
[花了我一段时间才弄清楚这个解决方案(尤其是捕获阶段的技巧和SyntheticEvent.nativeEvent.stopImmediatePropagation
vs. stopPropagation
问题),在网上其他任何地方我都没有看到这个中间按钮可吞咽的解决方案,因此将其发布在此处,以帮助下一个搜索解决方案的人。
[一种替代解决方案可能是添加一个polyfill,将Safari的不良SyntheticEvent
事件替换为符合标准的SyntheticEvent
事件,但是Google stopPropagation
和编写事件Polyfill超出了我对React事件处理的了解,所以我选择了上面的包装器组件解决方案。