如何在所有 onclick
之前运行代码React 应用程序中的处理程序而无需向每个处理程序添加代码?具体来说,我想全局确保所有 React onclick
都忽略中键点击。处理程序。目标是围绕 12-year-old WebKit bug 进行工作其中 Safari 发出 click
按下鼠标中键时的事件,而不是 auxclick
事件是 mandated由 Chrome 和 Firefox 发布的 W3C 标准。
由于某些用户在使用鼠标滚轮滚动时意外触发中键单击,因此我想全局忽略这些意外单击。怎么办?
我要注入(inject)的代码非常简单:
if (e.button !== 0) {
e.stopPropagation();
}
但我不确定在哪里注入(inject)它,以便它在我的应用程序中的所有事件处理程序之前运行。
一个潜在的复杂性是我不想完全忽略中键点击(因为浏览器有一个默认行为,即中键点击 <a>
元素将在新选项卡中打开链接)。相反,我只是想阻止 React 对那些无效的 click
做任何事情。事件。
最佳答案
为了解决这个问题,我认为我必须做一些棘手的事情,比如猴子修补 React,但事实证明,一个不棘手的解决方案是可能的:只需将整个应用程序包装在捕获点击事件的顶级组件中使用onClickCapture
事件而不是普通的点击事件。这是我为此目的编写的一个简单组件。
忽略SafariMiddleClicks.tsx
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>;
}
如果您不使用 TypeScript,这里是该组件的纯 JS 版本:
忽略SafariMiddleClicks.js
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>;
}
用法
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
在这种情况下不起作用,因为之后会继续调用其他 React 事件处理程序。我必须使用 SyntheticEvent
的 stopPropagation
方法.
我花了一段时间才找到这个解决方案(尤其是捕获阶段技巧和 stopPropagation
与 stopImmediatePropagation
问题),但我没有看到这个吞中按钮的解决方案可以在网上的任何其他地方找到,因此将其发布在这里以帮助下一个人搜索解决方案。
另一种解决方案可能是添加一个polyfill,用符合标准的auxclick
事件替换Safari的不良click
事件,但Google didn't return anything promising编写事件填充超出了我对 React 事件处理的有限知识,因此我选择了上面的包装组件解决方案。
关于reactjs - 如何在 React 应用程序中的所有 onclick 处理程序之前运行通用代码? (解决 Safari 中键点击错误),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59556495/