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

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

采用的是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']}
      />
  )}
/>
相关推荐
知了学历孙老师2 小时前
小自考的校考和统考,出题方和难度差在哪
java·大数据·前端
ShineWinsu4 小时前
对于JavaScript:操作元素的解析
开发语言·前端·javascript·面试·web·dom·元素
福兮说5 小时前
JSON 格式正确,数据就可靠吗?我用一份自编配置检查类型与空值
java·前端·json
程序员老赵7 小时前
Docker 部署青龙面板:轻松搭建定时任务管理平台
前端·docker·开源
Swot7 小时前
Asciidoctor 公式数字下标错位问题:原因分析与解决方案
前端
Swot7 小时前
leo-editor 中将 Markdown 内容转成 asciidoc 格式
前端
狒狒AI7 小时前
Remotion / GSAP+Three / HyperFrames / Skia 四栈实测:代码渲染知识视频的选栈方法(附开源技能)
前端·人工智能·aigc
修炼的dance7 小时前
浏览器里导出H.265,8.5秒和55.5秒差在硬件
前端
补码缩写7 小时前
WebCodecs选编码器,探测之后还要验解码和播放
前端
大文说跨境7 小时前
亚马逊多账号管理浏览器怎么选?云登/紫鸟/AdsPower 对比
java·前端·自动化