You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 23:32:14