shadcn/ui中一个SelectContent打开时,另一个SelectTrigger点击事件是否被阻塞?
问题原因与修复方案
这个问题的核心是shadcn/ui的Select基于Radix UI实现,Radix默认交互逻辑会在点击下拉框外部时关闭已打开的下拉,但当点击另一个Select的Trigger时,事件执行顺序会导致:先关闭当前打开的下拉,却没能触发目标Select的下拉打开(状态更新时机冲突),并非直接存在preventDefault或stopPropagation的阻塞,但默认逻辑的事件处理顺序导致了这个现象。
修复方法:手动控制Select的状态与交互逻辑
通过自定义onInteractOutside事件处理,结合状态同步来解决问题,代码示例如下:
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { useState, useRef } from "react"; export default function DoubleSelectFix() { const [open1, setOpen1] = useState(false); const [open2, setOpen2] = useState(false); const trigger1Ref = useRef<HTMLButtonElement>(null); const trigger2Ref = useRef<HTMLButtonElement>(null); const handleInteractOutside = (event: Event) => { const target = event.target as Node; // 判断点击目标是否是另一个Select的Trigger const isTrigger1 = trigger1Ref.current?.contains(target); const isTrigger2 = trigger2Ref.current?.contains(target); if (isTrigger1) { setOpen2(false); setOpen1(true); event.stopPropagation(); // 阻止默认外部关闭逻辑干扰当前点击 } else if (isTrigger2) { setOpen1(false); setOpen2(true); event.stopPropagation(); } else { // 正常外部点击,关闭所有下拉 setOpen1(false); setOpen2(false); } }; return ( <div className="flex gap-4 p-6"> <Select open={open1} onOpenChange={setOpen1}> <SelectTrigger ref={trigger1Ref} className="w-[180px]"> <SelectValue placeholder="选择项组1" /> </SelectTrigger> <SelectContent> <SelectItem value="1-1">选项1-1</SelectItem> <SelectItem value="1-2">选项1-2</SelectItem> </SelectContent> </Select> <Select open={open2} onOpenChange={setOpen2}> <SelectTrigger ref={trigger2Ref} className="w-[180px]"> <SelectValue placeholder="选择项组2" /> </SelectTrigger> <SelectContent onInteractOutside={handleInteractOutside}> <SelectItem value="2-1">选项2-1</SelectItem> <SelectItem value="2-2">选项2-2</SelectItem> </SelectContent> </Select> </div> ); }
逻辑说明
- 手动维护两个Select的
open状态,通过ref获取各自的Trigger元素 - 重写第二个SelectContent的
onInteractOutside方法:- 检测点击目标是否是另一个Select的Trigger
- 如果是,同步关闭当前下拉并打开目标下拉,同时阻止事件传播,避免Radix默认的外部关闭逻辑打断目标Trigger的点击事件
- 非Trigger的外部点击,正常关闭所有下拉
这样处理后,当第二个下拉打开时点击第一个Trigger,会立即关闭第二个下拉并打开第一个下拉,解决了需要点击两次的问题。
内容的提问来源于stack exchange,提问作者sonphung.xf
相关产品推荐
相关产品推荐

