MUI v7.2 Select组件在Vaul Drawer首次渲染时下拉菜单无法正常关闭的问题
MUI v7.2 Select组件在Vaul Drawer首次渲染时下拉菜单无法正常关闭的问题
这个问题的核心原因大概率是MUI Select的下拉菜单(Menu)默认通过Portal挂载到document.body上,而Vaul Drawer的DOM层级、事件拦截机制和首次渲染的初始化逻辑之间产生了冲突——首次打开抽屉时,body上的Menu无法正确监听点击外部的事件(抽屉可能拦截了这些事件),但抽屉关闭再打开后,DOM状态重新初始化,事件绑定恢复正常。
结合你提供的代码,我给出以下几个针对性的解决方案,按优先级排序:
方案1:将Menu挂载到Drawer内部(最推荐)
通过把Menu的渲染容器指定为Vaul Drawer的DOM节点,让Menu和Drawer处于同一层级,避免事件拦截问题:
- 首先给Vaul Drawer添加ref:
import { useRef } from 'react'; // 组件内部定义ref const drawerRef = useRef<HTMLDivElement>(null); // 在Vaul Drawer上绑定ref <Vaul.Drawer ref={drawerRef}> {/* 你的FormControl和Select代码放在这里 */} </Vaul.Drawer>
- 修改Select的
MenuProps,添加container属性指向drawerRef:
<Select multiple value={selectedUsers!} onChange={(e) => setSelectedUsers(e.target.value as string[])} renderValue={(selected) => selected.join(", ")} input={<OutlinedInput label="Select PI" />} MenuProps={{ // 关键:将Menu挂载到Drawer内部 container: drawerRef.current, PaperProps: { sx: { maxHeight: 250, overflowY: "auto", borderRadius: "16px", mt: 1, }, }, // 可选:手动增强关闭逻辑的可靠性 onClose: (event, reason) => { if (reason === 'backdropClick' || reason === 'escapeKeyDown') { // 这里不需要额外操作,MUI内部会处理关闭,但显式声明可以确保触发时机 } } }} sx={{ borderRadius: "100px", backgroundColor: "#F1F1F1" }} > {/* 你的MenuItem选项 */} </Select>
方案2:强制Select在Drawer打开后重新渲染
通过给Select添加动态key,让它在抽屉首次打开时重新渲染,确保Menu的事件绑定正确:
- 管理抽屉的打开状态:
import { useState } from 'react'; const [isDrawerOpen, setIsDrawerOpen] = useState(false); // 抽屉的打开/关闭回调 const handleDrawerToggle = () => { setIsDrawerOpen(prev => !prev); };
- 给Select添加
key={isDrawerOpen}:
<Select key={isDrawerOpen} // 抽屉状态变化时强制重渲染Select multiple value={selectedUsers!} onChange={(e) => setSelectedUsers(e.target.value as string[])} // 其他属性保持不变 > {/* 你的MenuItem选项 */} </Select>
额外注意:修正代码中的语法错误
我注意到你提供的MenuItem里有一个未闭合的Typography标签:
<Typography>{user.lastName}, {user.firstName<Typography>
这会导致DOM渲染异常,甚至间接影响组件的事件逻辑,务必修正为:
<Typography>{user.lastName}, {user.firstName}</Typography>
为什么disablePortal: true会导致菜单不可见?
当你设置disablePortal: true时,Menu会直接渲染在Select的父元素内部,而你的Select的sx设置了borderRadius: "100px"和背景色,可能导致Menu被父元素的溢出隐藏(overflow)挡住了。如果要使用这个选项,需要给Select的父元素(FormControl)添加overflow: "visible"的样式,但这个方案不如方案1可靠,因为可能引入新的布局问题。
内容来源于stack exchange
相关产品推荐
相关产品推荐

