如何实现支持键盘访问、交互时挂载Button的高性能React Card组件
完整修改后代码
import { useState, Fragment, useEffect, useRef, MutableRefObject } from "react"; import Button from "./Button"; export default function Card() { const [isHovered, setIsHovered] = useState<boolean>(false); const [showButtons, setShowButtons] = useState<boolean>(false); const containerRef: MutableRefObject<HTMLDivElement | null> = useRef(null); // 新增:卡片外层容器ref const cardWrapperRef: MutableRefObject<HTMLDivElement | null> = useRef(null); // 新增:存储键盘导航方向,forward正向tab,backward反向shift+tab const navDirectionRef = useRef<'forward' | 'backward'>('forward'); useEffect(() => { setShowButtons(isHovered); }, [isHovered]); // 新增:按钮显示后自动聚焦对应位置的按钮,同时调整卡片容器的可聚焦状态 useEffect(() => { if (showButtons && containerRef.current && cardWrapperRef.current) { // 等待按钮DOM渲染完成后执行 window.requestAnimationFrame(() => { const buttons = containerRef.current?.querySelectorAll<HTMLButtonElement>('button') || []; if (buttons.length === 0) return; // 根据导航方向聚焦第一个/最后一个按钮 if (navDirectionRef.current === 'forward') { buttons[0].focus(); } else { buttons[buttons.length - 1].focus(); } // 按钮显示后将卡片容器设为不可聚焦,避免tab重复切到容器 cardWrapperRef.current.tabIndex = -1; }); } else if (cardWrapperRef.current) { // 按钮隐藏后恢复卡片容器的可聚焦性 cardWrapperRef.current.tabIndex = 0; } }, [showButtons]); return ( <div ref={cardWrapperRef} onMouseOver={() => setIsHovered(true)} onMouseLeave={() => setIsHovered(false)} onFocus={(event) => { event.persist(); setIsHovered(true); }} onBlur={(event) => { event.persist(); window.requestAnimationFrame(() => { if (containerRef.current) { setIsHovered( containerRef.current.contains(document.activeElement) === true ); } }); }} // 新增:监听tab按键记录导航方向 onKeyDown={(e) => { if (e.key === 'Tab') { navDirectionRef.current = e.shiftKey ? 'backward' : 'forward'; } }} tabIndex={0} > <div ref={containerRef}> <h2>Card</h2> {showButtons && ( <Fragment> <Button>Expensive Button One</Button> <Button>Expensive Button Two</Button> </Fragment> )} </div> </div> ); }
核心修改说明
- 新增导航方向标识:通过
onKeyDown监听Tab按键,提前记录用户是正向(Tab)还是反向(Shift+Tab)导航进入卡片 - 新增按钮自动聚焦逻辑:当
showButtons变为true、按钮渲染完成后,根据导航方向自动聚焦第一个/最后一个按钮,无需额外按一次Tab - 动态调整卡片容器可聚焦性:按钮显示时将卡片外层容器的
tabIndex设为-1,避免Tab导航时重复选中容器;按钮隐藏时恢复tabIndex=0保证后续可正常聚焦卡片
内容的提问来源于stack exchange,提问作者tdc
相关产品推荐
相关产品推荐

