antd v3 select自定义下拉框内容失去焦点时会关闭下拉框

antd 版本 3.19.3 先说一下我遇到的问题,项目中需要做多日期对比,本来想使用 DatePicker 组件,每次选择一个日期,不能一次选择多个,操作起来相对有点麻烦(虽说实现起来很容易),于是,就想结合 SelectCalendar 组件一起使用,想法是很美好的,操作起来就困难重重了,我想要的效果如下图:

采用的是Select 的中 dropdownRender自定义下拉框内容,但是自定义内容中包含Select的话就会因失去焦点而关闭,无法进行二次选择,于是上网查了很多资料,都说如下方法可以解决这个问题,尝试了很多次都无效,不知道是不是我写法不对?时间很紧,不能因为一种方法而卡死,于是就换了一种思路,自己写一个类似Select的组件不就行了,这样就不会又失去焦点的问题了,于是就选择了Dropdown,只要效果一样,谁在乎你怎么实现的。

javascript 复制代码
<Select
  dropdownRender={() => (
    <div
      onMouseDown={(e) => {
        e.preventDefault();
        e.stopPropagation();
      }}
    >
      Some Content
    </div>
  )}
/>

对于 Calendar组件,要使用dateFullCellRender,重新设置单元格,方便添加选中样式,只需要稍微修改一下样式就可以了。

css 复制代码
// CalendarPage.css
.my_calendar .ant-fullcalendar-cell .ant-fullcalendar-selected-day .ant-fullcalendar-value {
  color: #fff !important;
  background: #1677ff !important;
}

.my_calendar .ant-fullcalendar-cell.ant-fullcalendar-selected-day .ant-fullcalendar-value {
  color: unset;
  background: unset;
}

.my_calendar_menu {
  max-height: 300px;
  overflow: auto;
}

Calendar组件二次封装

javascript 复制代码
import React from 'react';
import { Calendar, Card, Row, Col, Menu, Dropdown, Button } from 'antd'
import { DownOutlined } from '@ant-design/icons'
import moment from 'moment'
import './CalendarPage.css'
const dateFormat = 'YYYY-MM-DD'
export default function CalendarPage(props) {
  const { values, handleSelect, ...resProps } = props
  return (
    <Card
      bodyStyle={{ padding: 0, width: 300 }}
      onMouseDown={e => {
        e.preventDefault()
      }}
      style={{ width: 300 }}
    >
      <Calendar
        headerRender={({ value, type, onChange, onTypeChange }) => {
          const start = 0
          const end = 12
          const monthOptions = []
          const current = value.clone()
          const localeData = value.localeData()
          const months = []
          for (let i = 0; i < 12; i++) {
            current.month(i)
            months.push(localeData.monthsShort(current))
          }
          for (let index = start; index < end; index++) {
            monthOptions.push(
              <Menu.Item className="month-item" key={`${index}`}>
                {months[index]}
              </Menu.Item>
            )
          }
          const month = value.month()
          const year = value.year()
          const options = []
          for (let i = year - 10; i < year + 10; i += 1) {
            options.push(
              <Menu.Item key={i} value={i} className="year-item">
                {i}
              </Menu.Item>
            )
          }
          const menu = (
            <Menu
              size="small"
              onClick={newYear => {
                const now = value.clone().year(newYear.key)
                onChange(now)
              }}
              className="my_calendar_menu"
            >
            	{options}
            </Menu>
          )
          const menu2 = (
            <Menu
              size="small"
              onClick={selectedMonth => {
                const newValue = value.clone()
                newValue.month(parseInt(selectedMonth.key, 10))
                onChange(newValue)
              }}
              className="my_calendar_menu"
            >
            	{monthOptions}
            </Menu>
          )
          return (
            <div style={{ padding: 10 }}>
              <Row type="flex" justify="end">
                <Col>
                  <Dropdown size="small" overlay={menu}>
                    <Button>
                      {String(year)}
                      <DownOutlined />
                    </Button>
                  </Dropdown>
                </Col>
                <Col>
                  <Dropdown size="small" overlay={menu2}>
                    <Button style={{ marginLeft: 10 }}>
                      {months[month]}
                      <DownOutlined />
                    </Button>
                  </Dropdown>
                </Col>
              </Row>
            </div>
          )
        }}
        fullscreen={false}
        className="calendar"
        dateFullCellRender={date => {
          let de = moment(date).format(dateFormat)
          let cls = ''
          if (values && values.indexOf(de) !== -1) {
            cls = 'ant-fullcalendar-selected-day'
          } else {
            cls = ''
          }
          return (
            <div
              className={cls}
              onClick={() => {
                handleSelect && handleSelect(moment(date).format(dateFormat))
              }}
            >
              <div className="ant-fullcalendar-value" style={{ textAlign: 'center' }}>
                {moment(date).date()}
              </div>
            </div>
          )
        }}
        {...resProps}
      />
    </Card>
  )
}

使用

javascript 复制代码
// 引入 CalendarPage 组件
import CalendarPage from './CalendarPage'
<Select
  dropdownRender={() => (
      <CalendarPage
      	handleSelect={e=>{
      		// 逻辑处理,动态设置values
      	}
      	values={['2023-06-01', '2023-06-25']}
      />
  )}
/>
相关推荐
START_GAME11 分钟前
MSSQL$SQL2016
java·服务器·前端
Captaincc18 分钟前
Show me your works & token -稀土掘金上线内测作品广场和用量统计
前端·掘金社区·vibecoding
进击的明明31 分钟前
闭包:JavaScript里的“随身背包” 🎒
前端·javascript·面试
紫幽1 小时前
从 0 用 Vue 做屏并生成 LVGL 单片机代码(完整源码备忘)
前端·单片机
郭邯1 小时前
用 AI 辅助开发一个文件大小转换工具:从需求到上线的完整过程
前端
勾勾圈圈蛋蛋1 小时前
前中台项目
前端
触底反弹2 小时前
🔐 前端鉴权不再难!手把手带你搞懂 JWT + Zustand + Axios 的完整登录方案
前端·axios
打呵欠的猫2 小时前
我用 AI 写了一个"需求翻译器",产品的 PRD 直接变成开发任务清单
前端·ai编程
fatcoder2 小时前
玩转Nginx 09 — 运维排障:三场"火灾"实战演练
前端·后端·nginx
前端玩坑坑2 小时前
View Transitions API 入门教程,优雅过度
前端