You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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处于同一层级,避免事件拦截问题:

  1. 首先给Vaul Drawer添加ref:
import { useRef } from 'react';

// 组件内部定义ref
const drawerRef = useRef<HTMLDivElement>(null);

// 在Vaul Drawer上绑定ref
<Vaul.Drawer ref={drawerRef}>
  {/* 你的FormControl和Select代码放在这里 */}
</Vaul.Drawer>
  1. 修改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的事件绑定正确:

  1. 管理抽屉的打开状态:
import { useState } from 'react';

const [isDrawerOpen, setIsDrawerOpen] = useState(false);

// 抽屉的打开/关闭回调
const handleDrawerToggle = () => {
  setIsDrawerOpen(prev => !prev);
};
  1. 给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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.07 12:17:59