React中如何阻止遮罩层显示后按回车触发按钮onClick事件
解决方案
问题根源在于:按钮点击后仍保留焦点,按下回车会触发按钮的默认点击行为;而遮罩层默认不具备焦点捕获能力,无法拦截键盘事件。以下是针对性的修复方案:
1. 按钮点击后主动失焦
在按钮点击事件中让按钮失去焦点,从根源避免回车再次触发点击:
修改Dashboard组件,通过useRef获取按钮引用,点击后调用blur():
import React, { useRef } from "react"; import { useOverlay } from "./OverlayContext"; function Dashboard() { const { CreateOverlay } = useOverlay(); const buttonRef = useRef(null); function handleClick(e) { e.preventDefault(); e.stopPropagation(); CreateOverlay("Now press ENTER and it won't trigger again."); // 按钮失焦,切断回车触发路径 buttonRef.current?.blur(); } return ( <> <div>Click the button!</div> <button ref={buttonRef} onClick={(e) => handleClick(e)}> Show overlay </button> </> ); } export default Dashboard;
2. 让遮罩层具备焦点捕获能力
修改遮罩层元素,使其能够接收焦点并拦截键盘事件,防止焦点回流到按钮或其他页面元素:
修改OverlayContext中的遮罩层渲染逻辑,添加tabIndex、自动聚焦和键盘事件处理:
import { createContext, useContext, useState, useEffect, useRef } from "react"; export const OverlayContext = createContext(); export function useOverlay() { return useContext(OverlayContext); } export const OverlayProvider = ({ children }) => { const [overlays, setOverlays] = useState([]); const latestOverlayRef = useRef(null); function CreateOverlay(text) { const newOverlay = { id: Date.now(), text }; setOverlays((o) => [...o, newOverlay]); return newOverlay; } // 每次新增遮罩层时,聚焦最上层的遮罩 useEffect(() => { if (latestOverlayRef.current) { latestOverlayRef.current.focus(); } }, [overlays]); return ( <OverlayContext.Provider value={{ CreateOverlay }}> {overlays.length > 0 && overlays.map((o, index) => { const isLatest = index === overlays.length - 1; return ( <div className="overlay" key={o.id} tabIndex="-1" ref={isLatest ? latestOverlayRef : null} onKeyDown={(e) => { // 阻止Tab键将焦点移出遮罩层 if (e.key === "Tab") { e.preventDefault(); } }} > {o.text} </div> ); })} {children} </OverlayContext.Provider> ); };
3. 补充CSS确保遮罩层层级正确
确保遮罩层的样式能覆盖页面内容,多个遮罩层时上层遮罩优先级更高:
.overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); color: white; display: flex; align-items: center; justify-content: center; z-index: 1000; } /* 多个遮罩层时,后续的遮罩层级递增 */ .overlay:nth-child(n+2) { z-index: 1001; }
关键说明
- 按钮失焦:直接切断回车触发按钮点击的路径,简单有效。
- 遮罩层聚焦:确保键盘事件被遮罩层捕获,即使按钮未失焦,焦点在遮罩层时回车也不会触发按钮。
- 多遮罩层支持:用唯一
id作为key避免渲染异常,同时让最新的遮罩层获得焦点,保证用户操作的是最上层遮罩。
内容的提问来源于stack exchange,提问作者Galbert
相关产品推荐
相关产品推荐

