基于 ant-design Calendar组件集成农历选择器 react

前言

终于开启第二篇文章了,上一篇还是三年前,本人技术栈一直以vue为主,最近开始接触一些react的项目,简单写了一些组件,感觉和vue核心思想差不多,不过差别也是有的。好了,框架不重要,接下来进入正题。

效果图

话不多说,先上效果图,该组件使用react开发框架,基于ant-design 里的Calendar 组件,使用了lunar-javascript日历工具库对日历单元格进行农历日期的渲染。过程很简单,但在没找到门路之前也走了很多弯路,所以在此记录一下。
在这里插入图片描述

思路

先把我们要用到的插件引进来,这里用到了ant-design的模态框,日历,tag标签,以及lunar日历库。

import { Modal, Calendar, Tag} from 'antd';
import { CloseCircleOutlined } from '@ant-design/icons';
import { Lunar,Solar } from 'lunar-javascript';

接下来放我们的日历组件

const [isModalOpen, setIsModalOpen] = useState(false)
const [onSelectDate, setOnSelectDate] = useState([])
const [calendarDate, setCalendarDate] = useState(moment(new Date())); 

const showModal = () => {
  setIsModalOpen(true);
};
const handleOk = () => {
  setIsModalOpen(false);
};
const handleCancel = () => {
  setIsModalOpen(false)
};

return (
 	<>
	 <button onClick={showModal} >农历日期选择</button>
	 <Modal 
	 	title="农历日期选择" 
	 	getContainer={false} 
	 	open={isModalOpen} 
	 	onOk={handleOk} 
	 	onCancel={handleCancel}
	    footer={[<Button className="clo-btn" key="back" onClick={handleOk}>确认</Button>]}
	 >
	    <Calendar dateCellRender={dateCellRender}  className="site-calendar" fullscreen={false} onSelect={onSelect}/>
	    <div className='selectedDate'>已选:{renderSelectedDate()}</div>
	</Modal>
	</>
)

利用dateCellRender对Calendar日历单元格的重写,加上农历日期:

const dateCellRender = (date) => {
    const d = date._d
    const solar = Solar.fromDate(d);
    const lunar = solar.getLunar();
    // 将数字形式的农历年月日放到数组里
    const lunarDateArab = [lunar.getYear(),lunar.getMonth(),lunar.getDay()] 
    // 将中文形式的农历年月日放到数组里
    const lunarDateChin = [Lunar.fromDate(d).toString().substr(0,4),Lunar.fromDate(d).toString().substr(5,2),Lunar.fromDate(d).toString().substr(7,2)] 
    const lunarSL = Lunar.fromYmd(lunarDateArab[0], lunarDateArab[1], lunarDateArab[2]);
    const festival = lunarSL.getFestivals(); // 获取农历节日
    const jieQi = lunarSL.getJieQi() // 获取节气
    let showDate = lunarDateChin[2]
    if(lunarDateChin[2] == '初一') {
      showDate = lunarDateChin[1]
    }
    if (jieQi) {
      showDate = jieQi
    }
    if (festival.length > 0) {
      showDate = festival[0]
    }
    return (
      <div>
        <div className='lunarStyle'>{showDate}</div>
      </div>
    );
  };

到这里,农历日期展示就可以了。接下来是对农历的日期进行选择、展示、删除的功能。

 // 点击日历选择某个日期
 const onSelect = (value, mode) => {
    let flag = true
    // 这里防止用户选择年和月的时候选中日期
    if (!calendarDate.isSame(value, 'month') || !calendarDate.isSame(value, 'year')) {
      setCalendarDate(value);
      return;
    }
    const d = value._d
    const solar = Solar.fromDate(d);
    const lunar = solar.getLunar();
    const lunarDateArab = [lunar.getYear(),lunar.getMonth(),lunar.getDay()]
    const lunarDateChin = [Lunar.fromDate(d).toString().substr(0,4),Lunar.fromDate(d).toString().substr(5,2),Lunar.fromDate(d).toString().substr(7,2)]
    const lunarSL = Lunar.fromYmd(lunarDateArab[0], lunarDateArab[1], lunarDateArab[2]);
    const festival = lunarSL.getFestivals();
    const jieQi = lunarSL.getJieQi()
    let arr = JSON.parse(JSON.stringify(onSelectDate))
    let showDate = lunarDateChin[1] + lunarDateChin[2]
    if (festival.length > 0) {
      showDate = festival[0]
    }
    arr.forEach((e) => {
      if(e.chin == showDate) {
        flag = false
      }
    })
    // 加flag防止选择到重复的日期
    if(flag) {
    	// 由于后端需要农历的数字形式和中文形式,所以这里设置了chin 放农历中文,arab放数字
      arr.push({'chin': showDate, 'arab': lunar.getMonth() + '.' + lunar.getDay()})
      setOnSelectDate(arr)
    }
  };
  // 已选tag签的渲染
  const renderSelectedDate = () => {
    return onSelectDate.map((item, index) => {
      return (
        <span className='selectedDate-item'>
          <Tag key={item.chin} closable closeIcon={<CloseCircleOutlined />}  onClose={() => handleClose(item)}>
              {item.chin}
          </Tag>
        </span>
      )
    })
  }
  // 删除已选日期
  const handleClose = (value) => {
    let arr = JSON.parse(JSON.stringify(onSelectDate))
    arr = arr.filter(item => item.chin !== value.chin)
    setOnSelectDate(arr)
  };

问题

在开发过程中遇到了两个问题,一个是Calendar组件的onSelect,用户无论点击日期还是月份年份都会触发onSelect,所以加了下面这个判断,calendarDate里存放日历里上一个选中的日期,当触发了onSelect时对选中日期和上一个日期年份和月份进行对比,如果年份月份有一个变了,说明用户可能对年份和月份进行了选择,如果年份和月份都没变,则说明用户选择了某个日期。

if (!calendarDate.isSame(value, 'month') || !calendarDate.isSame(value, 'year')) {
	setCalendarDate(value);
	return;
}

第二个问题是tag标签的,除了最后一个标签点击删除没问题外,点击其他标签的删除会直接删掉两个tag,这是由于之前为了图省事,tag标签里的key的值简单粗暴的用了index,而tag标签在删除的时候会通过这个关键 key 来删除数组中的对应元素,而index在标签删除后会发生改变,所以这里的key一定要用一个唯一的id。

写在最后

以上就是关于农历日历的分享,简单但细节满满,上面代码其实可以更加精简一些,但我马不停蹄的奔向下一需求了,就这么着了。欢迎大神们批评指正,也希望能给困惑中的你一点点解题思路~

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
要修改 ant-design-pro DatePicker 季度选择组件,您需要按照以下步骤进行操作: 1. 导入 `DatePicker` 组件: ```javascript import { DatePicker } from 'antd'; ``` 2. 在 `DatePicker` 组件中使用 `mode` 属性设置为 `quarter`,以启用季度选择: ```javascript <DatePicker mode="quarter" /> ``` 3. 如果您想要修改季度选择的样式或行为,可以通过 `picker` 属性传递一个自定义的季度选择组件。您可以创建一个新的组件并将其传递给 `picker` 属性: ```javascript import { DatePicker } from 'antd'; import QuarterPicker from './QuarterPicker'; <DatePicker picker={<QuarterPicker />} /> ``` 4. 在自定义季度选择组件中,您可以按照 antd 的 DatePicker API 来构建组件,根据您的需求进行修改。例如,您可以添加一个 `QuarterPicker` 组件,它包含了四个季度按钮,并在用户选择一个季度时将其传递回父组件: ```javascript import React from 'react'; import { DatePicker } from 'antd'; const QuarterPicker = ({ onChange }) => { const handleQuarterChange = (quarter) => { onChange(quarter); }; return ( <div> <button onClick={() => handleQuarterChange(1)}>Q1</button> <button onClick={() => handleQuarterChange(2)}>Q2</button> <button onClick={() => handleQuarterChange(3)}>Q3</button> <button onClick={() => handleQuarterChange(4)}>Q4</button> </div> ); }; export default QuarterPicker; ``` 通过以上步骤,您可以自定义 ant-design-pro DatePicker 季度选择组件

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhuantou000

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值