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

MUI多选选择器:实现多选时不关闭下拉菜单,且完成选择后再提交选中项数组

MUI多选选择器:实现多选时不关闭下拉菜单,且完成选择后再提交选中项数组

看起来你已经在MUI的多选Select组件上搭好了基础框架,现在的核心需求是从「选一个月份就立即更新父组件的选中数组」,改成「让用户选完所有想要的月份后,再一次性提交选中项数组」对吧?我来帮你调整代码解决这个问题~

问题根源分析

你原来的代码里,handleChange直接调用了父组件传过来的setSelectedMonths,所以每选一个选项就会立即更新父组件状态。我们需要新增一个本地临时状态来存储用户的实时选择,等用户确认后再同步给父组件,同时保留多选时菜单不关闭的逻辑。

修改后的完整代码

import { useState, useRef } from 'react';
import { FormControl, InputLabel, Select, OutlinedInput, MenuItem, Checkbox, ListItemText, Box, Button } from '@mui/material';

const MonthPicker = ({ monthsList, selectedMonths, setSelectedMonths }) => {
  // 新增本地临时状态,实时存储用户选择,不直接触发父组件更新
  const [tempSelectedMonths, setTempSelectedMonths] = useState(selectedMonths);
  // 用来获取菜单实例,方便点击确认后关闭菜单
  const menuListRef = useRef(null);

  // 处理选项选择,更新临时状态
  const handleChange = (event) => {
    const { target: { value } } = event;
    setTempSelectedMonths(typeof value === "string" ? value.split(",") : value);
  };

  // 确认选择,同步临时状态到父组件,并关闭菜单
  const handleConfirmSelection = () => {
    setSelectedMonths([...tempSelectedMonths]);
    // 关闭下拉菜单
    if (menuListRef.current) {
      const menuElement = menuListRef.current.closest('[role="menu"]');
      if (menuElement) menuElement.style.display = 'none';
    }
  };

  const MenuProps = {
    disableAutoFocusItem: true,
    // 给菜单添加ref,方便后续关闭
    MenuListProps: {
      ref: menuListRef,
      // 禁止菜单点击空白处关闭(可选,根据需求调整)
      onMouseDown: (e) => e.stopPropagation(),
    },
  };

  return (
    <FormControl
      sx={{
        width: "100%",
        "& .MuiInputLabel-root": {
          fontSize: "1rem",
          color: Colors.dark,
        },
        "& .MuiSelect-root": {
          fontSize: "0.8rem",
        },
      }}
      size="small"
    >
      <InputLabel id="month-picker-label">Oyni Tanlash</InputLabel>
      <Select
        multiple
        labelId="month-picker-label"
        id="month-picker"
        value={tempSelectedMonths}
        onChange={handleChange}
        input={<OutlinedInput label="Oyni Tanlash" />}
        renderValue={(selected) => selected.join(", ")}
        MenuProps={MenuProps}
      >
        {monthsList.map((month) => (
          <MenuItem
            key={month.id}
            value={month.name}
            sx={{
              padding: "4px 8px",
              display: "flex",
              alignItems: "center",
              gap: "8px",
            }}
            // 阻止点击选项时关闭菜单
            onClick={(event) => event.stopPropagation()}
          >
            <Checkbox
              checked={tempSelectedMonths.includes(month.name)}
              sx={{ color: Colors.blue_nbu, padding: 0 }}
              size="small"
            />
            <ListItemText
              primary={month.name}
              sx={{ fontSize: "0.8rem", margin: 0 }}
            />
          </MenuItem>
        ))}
        {/* 添加确认与取消按钮 */}
        <MenuItem
          sx={{
            borderTop: "1px solid #eee",
            justifyContent: "flex-end",
            padding: "8px 16px",
          }}
          onClick={(e) => e.stopPropagation()}
        >
          <Box sx={{ display: "flex", gap: "8px" }}>
            <Button
              size="small"
              variant="outlined"
              onClick={() => {
                // 重置临时选择并关闭菜单
                setTempSelectedMonths(selectedMonths);
                const menuElement = menuListRef.current?.closest('[role="menu"]');
                if (menuElement) menuElement.style.display = 'none';
              }}
            >
              Bekor qilish
            </Button>
            <Button
              size="small"
              variant="contained"
              onClick={handleConfirmSelection}
              sx={{ backgroundColor: Colors.blue_nbu }}
            >
              Tasdiqlash
            </Button>
          </Box>
        </MenuItem>
      </Select>
    </FormControl>
  );
};

关键改动说明

  1. 本地临时状态:新增tempSelectedMonths来实时存储用户的选择,用户选选项时只会更新本地状态,不会触发父组件的状态更新,实现“暂存选择”的效果。
  2. 确认按钮逻辑:在菜单底部添加了“确认”和“取消”按钮,点击“确认”才会把临时选择同步给父组件的selectedMonths,点击“取消”则重置临时状态并关闭菜单。
  3. 菜单关闭控制:用useRef获取菜单实例,点击按钮后手动关闭菜单,同时保留了原来的event.stopPropagation()来防止选选项时菜单意外关闭。
  4. 初始状态同步:初始化临时状态时绑定父组件传的selectedMonths,保证编辑场景下能正确显示已选中的内容。

这样调整后,用户就可以在下拉菜单里自由选择多个月份,选完后点击确认才会提交选中的数组,完全符合你的需求啦~

备注:内容来源于stack exchange,提问作者Ogabek Otaxonov

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 16:04:34