如何在按下TAB键移出表单时关闭ResultList组件?
解决方案
核心思路:利用focusout事件精准判断焦点移出范围
放弃点击外部的逻辑,改用表单的focusout事件,通过relatedTarget属性获取新焦点的元素,判断其是否属于表单内部,若不属于则关闭ResultList。
import { useRef, useState } from 'react'; function SearchForm() { const [isSearchActive, setIsSearchActive] = useState(false); const innerRef = useRef(null); const handleFormFocusOut = (e) => { // 新焦点元素不在表单范围内时,关闭结果列表 if (innerRef.current && !innerRef.current.contains(e.relatedTarget)) { setIsSearchActive(false); } }; return ( <form ref={innerRef} onFocusOut={handleFormFocusOut} > <input type="text" onChange={() => setIsSearchActive(true)} // 输入时开启结果列表 /> {isSearchActive && <ResultList />} <button type="submit">提交</button> </form> ); }
原方案失效原因
按下TAB键切换焦点时,焦点切换是瞬间完成的,点击外部的事件触发时机过早,此时e.target仍停留在表单内的元素上,导致contains判断为true,无法触发状态变更。而focusout事件会在元素完全失去焦点后触发,relatedTarget已经指向新的焦点元素,能准确判断是否移出了表单区域。
可选方案:针对TAB键的特殊处理(不推荐)
若仅需响应TAB键的场景,可结合定时器延迟判断焦点状态,但这种方法依赖异步时机,可靠性不如focusout:
const handleTabKeyDown = (e) => { if (e.key === 'Tab') { setTimeout(() => { if (innerRef.current && !innerRef.current.contains(document.activeElement)) { setIsSearchActive(false); } }, 0); } };
给表单添加onKeyDown={handleTabKeyDown}即可使用此逻辑。
内容的提问来源于stack exchange,提问作者Eirik Vattøy
相关产品推荐
相关产品推荐

