如何在React应用中的所有onclick处理程序之前运行通用代码? (以解决Safari中键单击错误)

问题描述 投票:1回答:1

如何在React应用程序中的所有onclick处理程序之前运行代码,而不必向每个处理程序添加代码?具体来说,我想全局确保所有React onclick处理程序都忽略中键单击。目标是解决12-year-old WebKit bug的问题,其中Safari在按下鼠标中键时会发出click事件,而不是W3C标准的auxclick事件(由Chrome和Firefox发出)auxclick事件。

由于一些用户在用鼠标滚轮滚动时意外触发了中键单击,因此我想全局地忽略这些意外单击。怎么样?

我要注入的代码非常简单:

mandated

但是我不确定在哪里注入它,以便它在我应用程序中的所有事件处理程序之前运行。

一个潜在的麻烦是,我不想完全忽略中间点击(因为浏览器的默认行为是,在if (e.button !== 0) { e.stopPropagation(); } 元素上中间点击会在新标签中打开链接)。相反,我只是想防止对那些无效的<a>事件做出任何反应。

reactjs mouseevent dom-events stoppropagation
1个回答
1
投票

为了解决这个问题,我认为我必须做一些棘手的事情,例如猴子补丁React,但事实证明,这可能是一种非精确的解决方案:只需将整个应用程序包装在一个顶层组件中,即可使用click事件,而不是普通的onClickCapture事件。这是我为此目的编写的一个简单组件。

IgnoreSafariMiddleClicks.tsx

onClickCapture

如果您不使用TypeScript,这是该组件的普通JS版本:

IgnoreSafariMiddleClicks.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事件处理的了解,所以我选择了上面的包装器组件解决方案。

© www.soinside.com 2019 - 2024. All rights reserved.