英文:
Why does React's onContextMenu work in Chrome on disabled elements?
问题
我发现了一些非常奇怪的事情。在所有主要的浏览器中,上下文菜单事件在禁用的元素上不起作用,所以这不会在控制台中打印出来:
<button
type="button"
onContextMenu={() => console.log(123)}
disabled
>
点我
</button>
但是在 React 中有点不同。我试图通过 React 组件来做同样的事情:
const MyComponent = () => (
<button
type="button"
onContextMenu={() => console.log(123)}
disabled
>
点我
</button>
);
这一次,在 Chrome 中会在控制台中打印,但在其他浏览器中不会。出于教育目的,我试图理解 HTML 的 onContextMenu
和 React 的 onContextMenu
之间的区别,以及为什么只有 Chrome 处理它不同。非常奇怪。
在 Codesandbox 中重现。
英文:
I found something very strange. In all major browsers, context menu event doesn't work on disabled elements, so this wouldn't print to console:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-html -->
<button
type="button"
onContextMenu="console.log(123)"
disabled
>
Click me
</button>
<!-- end snippet -->
But it's a little different with React. I tried to do the same thing through React component:
const MyComponent = () => (
<button
type="button"
onContextMenu={() => console.log(123)}
disabled
>
Click me
</button>
);
This time, in Chrome it prints to the console, but in other browsers it does not. For educational purpose, I'm trying to understand what is the difference between HTML's onContextMenu
and React's onContextMenu
plus why only Chrome handles it differently. Super weird.
Reproduced in Codesandbox
答案1
得分: 1
我花了一段时间研究这个问题。似乎这是Chrome中的一个 bug,即使contextmenu
是PointerEvent
的一种类型,在冒泡时仍然会触发在禁用的元素上。
这里有一个没有使用React的JSFiddle:https://jsfiddle.net/bpe0yoc6/4/
React在DOM树的根部注册事件处理程序,这就是为什么这样做不起作用的原因:
document.querySelector("button").addEventListener("contextmenu", (e) => { ... })
不会在禁用的按钮上触发,oncontextmenu
也一样。
我在Chromium问题跟踪器上提出了一个问题:https://bugs.chromium.org/p/chromium/issues/detail?id=1421370
英文:
I spent a while digging into this. It seems like a bug in Chrome where contextmenu
, despite being a type of PointerEvent
, fires on disabled elements but only when bubbling.
Here's a JSFiddle without React: https://jsfiddle.net/bpe0yoc6/4/
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
// Only in chrome does this fire
document.querySelector("#root").addEventListener("contextmenu", (e) => { console.log("contextmenu fired", e.target.tagName) })
document.querySelector("#root").addEventListener("click", (e) => { console.log("click fired", e.target.tagName) })
<!-- language: lang-css -->
#root {
width: 200px;
height: 200px;
display: block;
background-color: #ccc;
}
<!-- language: lang-html -->
<div id="root">
<button
type="button"
disabled
>
Click me
</button>
</div>
<!-- end snippet -->
React registers event handles at the root of the DOM tree, which is why doing this:
document.querySelector("button").addEventListener("contextmenu", (e) => { ... })
will not fire on the disabled button, and neither will oncontextmenu
.
I opened an issue on the Chromium issue tracker: https://bugs.chromium.org/p/chromium/issues/detail?id=1421370
答案2
得分: 1
根据Chromium,这是故意的。请查看问题跟踪器。
这是一个故意的更改,并与火狐夜间版实施的新行为相匹配。
由于其他问题,我暂时禁用了新的行为,但很快会重新启用。
禁用属性只应该阻止点击事件,而不是上下文菜单事件。你能在上下文菜单事件上调用preventDefault()吗?
听起来现在需要进行显式检查。
英文:
According to Chromium, this is intentional. See the issue tracker.
> This is an intentional change and matches what firefox nightly, who also implemented the new behavior, is doing.
> I have temporarily disabled the new behavior due to other issues, but I will re-enable it soon.
> The disabled attribute is only supposed to block click events, not contextmenu events. Can you just call preventDefault() on the contextmenu event?
Sounds like an explicit check is now required.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论