Dropdown下拉菜单点击外部区域无法收起怎么办?

诺曦 阅读 12

我用React写了一个带下拉菜单的组件,给document绑定了click事件来收起菜单,但有时候点击菜单内部链接也会触发收起,导致链接点不动。试过加stopPropagation也不行,代码大概是这样:


function Dropdown() {
  const [open, setOpen] = useState(false);
  const ref = useRef();

  useEffect(() => {
    const handleClick = (e) => {
      if (!ref.current.contains(e.target)) setOpen(false);
    };
    document.body.addEventListener('click', handleClick);
    return () => document.body.removeEventListener('click', handleClick);
    // 这里好像有问题?
  }, []);

  return (
    <div ref={ref}>
      <button onClick={() => setOpen(!open)}>Toggle</button>
      {open && <ul>
        <li><a href="#!" onClick={(e)=>e.stopPropagation()}>选项1</a></li>
      </ul>}
    </div>
  );
}

现在点击选项1链接时,菜单会同时关闭,导致链接无法触发。明明给a标签加了stopPropagation啊,到底是哪里漏了?

我来解答 赞 1 收藏
二维码
手机扫码查看
1 条解答
小倩~
小倩~ Lv1
问题出在事件冒泡的时机上,stopPropagation只阻止了子元素的冒泡,但你绑的是document的click事件,它还是会触发。改成这样:

function Dropdown() {
const [open, setOpen] = useState(false);
const ref = useRef();

useEffect(() => {
const handleClick = (e) => {
if (ref.current && !ref.current.contains(e.target)) {
setOpen(false);
}
};
document.body.addEventListener('click', handleClick);
return () => document.body.removeEventListener('click', handleClick);
}, []);

return (
<div ref={ref}>
<button onClick={(e) => { e.stopPropagation(); setOpen(!open); }}>Toggle</button>
{open && <ul>
<li><a href="#!" onClick={(e)=>{ e.stopPropagation(); alert('clicked'); }}>选项1</a></li>
</ul>}
</div>
);
}


关键点是在buttona标签上都加上stopPropagation,并且确保ref.current存在再调用contains,防止内存泄漏。别忘了给a标签加上具体的点击处理逻辑。
点赞 2
2026-02-16 21:00