antd-mobile DatePickervView封装按日按月组件(TS版本)

代码直接复制就可以,简单易懂,没有其他副作用。只要按组件接收的格式传入相对应格式即可,也可以自己改造~

用到前端语言:antd-mobile,react,typescript,less,dayjs

效果:可按月,按时间段筛选列表。按时间段选择时,当结束时间选择小于开始时间,组件会将两个值兑换后传给onOk方法。

时间选择组件接收三个字段,两个事件
month,startTime,endTime三个字段,type类型为string
onClose方法,点击取消的事件
onOk方法,点击确定的事件

字段说明:按月选择确定时,组件返回

// 字段说明:按月选择确定时,组件返回​​​​​​​
{month:'2022-03',startTime:'',endTime:''}

按日选择确定时,组件返回,需要根据endTime的具体值来判断时间选择后,页面时间文本怎么显示,当选择的结束时间小于开始时间时,组件会将两个值对换传给onOk方法。

// 按日选择确定时,组件返回
{month:'',startTime:'2022-03-22',endTime:'没有选择则等于startTime,选择了则为选择的时间'}

效果图:

150

页面代码

import { Button, DatePickerView, } from 'antd-mobile'
import dayjs from 'dayjs'
import React, { useEffect, useState } from 'react'
import styles from './index.module.scss'

// onOk事件的参数type
export interface ITimePropsOk {
  month: string
  startTime: string
  endTime: string
}

// 时间组件接收的props值type
interface ITimeDateModalProps {
  month: string
  startTime: string
  endTime: string
  onClose: () => void
  onOk: (data: ITimePropsOk ) => void
}

export const DateModal: React.FC<ITimeDateModalProps> = ({ month, startTime, endTime, onClose, onOk }) => {
  const [range, setRange] = useState('month') // 切换button月/日 month/day
  const [dayStep, setDayStep] = useState('start') // 切换时间段的开始/结束  start/end
  const [monthValue, setMonthValue] = useState<any>() // 月切换事件,设置当前DatePickerView的选择值
  const [dayValue, setDayValue] = useState<any>() // 日切换事件,设置当前DatePickerView的选择值
  const [monthText, setMonthText] = useState<any>('') // 按月选择-文本显示
  const [dayStartText, setDayStartText] = useState<any>('开始日期') // 按日选择-结束时间文本显示
  const [dayEndText, setDayEndText] = useState<any>('结束日期') // 按日选择-结束时间文本显示
  const maxDate = new Date(Date.now()) // DatePickerView最大可选的时间
  const minDate = new Date('2018-01-01') // DatePickerView最小可选的时间

  useEffect(() => {
    // 传过来的为月
    if (month) {
      setMonthValue(new Date(month))
      setDayValue(new Date(Date.now()))
      setMonthText(month)
      setDayStartText(dayjs(new Date(Date.now())).format('YYYY-MM-DD'))
    }
    // 传过来为时间段,设置第一个选择时间
    if (!month) {
      setRange('day')
      setMonthValue(new Date(Date.now()))
      setMonthText(dayjs(new Date(Date.now())).format('YYYY-MM'))
      setDayValue(new Date(startTime))
      setDayStartText(startTime)
      if (dayjs(startTime).format('YYYY-MM-DD') !== dayjs(endTime).format('YYYY-MM-DD')) {
        setDayEndText(endTime)
      }
    }
  }, [false])

  // 切换 月/日 的样式
  const setRangeButtonStyle = (text: string) => {
    return {
      background: `${range === text ? '#468CEA' : '#fff'}`,
      color: `${range === text ? '#fff' : '#666'}`,
      border: `${range === text ? 'none' : '0.07rem solid #EEEEEE'}`
    }
  }

  // 切换 时间段 的样式
  const setRangeDayStyle = (text: string) => {
    return {
      color: `${dayStep === text ? '#468cea' : '#666'}`
    }
  }

  // 切换 月/日
  const onRangeChange = (text: string) => {
    if (range === text) { return }
    setRange(text)
  }

  // 切换 时间段 开始/结束
  const onDayStepChange = (text: string) => {
    if (dayStep === text) { return }
    setDayStep(text)
    if (text === 'start') {
      setDayValue(new Date(dayStartText))
    } else {
      if (dayEndText == '结束日期') {
        setDayValue(new Date(Date.now()))
        setDayEndText(dayjs(new Date(Date.now())).format('YYYY-MM-DD'))
      } else {
        setDayValue(new Date(dayEndText))
      }

    }
  }

  const onMonthChange = (date: any) => {
    setMonthValue(date)
    setMonthText(dayjs(date).format('YYYY-MM'))
  }

  const onDayChange = (date: any) => {
    setDayValue(date)
    if (dayStep === 'start') {
      setDayStartText(dayjs(date).format('YYYY-MM-DD'))
    } else {
      setDayEndText(dayjs(date).format('YYYY-MM-DD'))
    }
  }

  const onConfirm = () => {
    if (range === 'month') {
      onOk({
        month: monthText,
        startTime: '',
        endTime: '',
      })
    } else {
      if (dayEndText === '结束日期') {
        onOk({
          month: '',
          startTime: dayStartText,
          endTime: dayStartText,
        })
      } else {
        if (new Date(dayStartText) > new Date(dayEndText)) {
          onOk({
            month: '',
            startTime: dayEndText,
            endTime: dayStartText,
          })
        } else {
          onOk({
            month: '',
            startTime: dayStartText,
            endTime: dayEndText,
          })
        }
      }
    }
  }

  return (
    <div className={styles.dateModal}>
      <div className={styles.dateMask}></div>
      <div className={styles.dateContent}>
        <div className={styles.topButtons}>
          <div onClick={onClose}>取消</div>
          <div onClick={onConfirm}>确定</div>
        </div>
        <div className={styles.range}>
          <Button className={styles.button} style={setRangeButtonStyle('month')} onClick={() => onRangeChange('month')}>按月选择</Button>
          <Button className={styles.button} style={setRangeButtonStyle('day')} onClick={() => onRangeChange('day')}>按日选择</Button>
        </div>
        <div className={styles.dateText}>
          {range === 'month' && (
            <div className={styles.monthText}>{monthText}</div>
          )}
          {range === 'day' && (
            <div className={styles.dayText}>
              <span style={setRangeDayStyle('start')} onClick={() => onDayStepChange("start")}>{dayStartText}</span>
              <span>至</span>
              <span style={setRangeDayStyle('end')} onClick={() => onDayStepChange("end")}>{dayEndText}</span>
            </div>
          )}

        </div>
        <div className={styles.dateSelect}>
          {range === 'month' && (
            <DatePickerView
              mode="month"
              minDate={minDate}
              maxDate={maxDate}
              value={monthValue}
              onChange={onMonthChange}
            />
          )}
          {range === 'day' && (
            <div>
              <DatePickerView
                mode="date"
                minDate={minDate}
                maxDate={maxDate}
                value={dayValue}
                onChange={onDayChange}
              />
            </div>
          )}
        </div>
      </div>

    </div>
  )
}

less样式

.dateModal {
    position: fixed;
    width: 100%;
    height: 100%;
    top: 0;
    left: 0;
    z-index: 1;
    .dateMask {
        position: absolute;
        width: 100%;
        height: 100%;
        top: 0;
        left: 0;
        z-index: 1;
        background: rgba(0, 0, 0, 0.25);
    }
    .dateContent {
        position: absolute;
        width: 100%;
        max-height: 28rem;
        bottom: 0;
        left: 0;
        z-index: 2;
        background: #fff;
        .topButtons {
            display: flex;
            align-items: center;
            justify-content: space-between;
            border-bottom: 0.03rem solid #e5e5e5;
            font-size: 1rem;
            font-weight: 400;
            color: #468cea;
            div {
                padding: 1.13rem 0.8rem 0.8rem;
            }
        }
        .range {
            padding: 1.33rem 1.33rem 1.4rem;
            display: flex;
            align-items: center;
            justify-content: flex-start;
            .button {
                width: 5.87rem;
                height: 2rem;
                border-radius: 0.27rem;
                font-weight: 400;
                font-size: 1rem;
                display: flex;
                align-items: center;
                justify-content: center;
                &:first-child {
                    margin-right: 0.67rem;
                }
            }
        }
        .dateText {
            width: 100%;
            height: 4rem;
            background: #f5f7f9;
            display: flex;
            align-items: center;
            justify-content: center;
            .monthText {
                font-size: 1.2rem;
                font-weight: 500;
                color: #468cea;
            }
            .dayText {
                display: flex;
                align-items: center;
                justify-content: center;
                span {
                    font-size: 0.93rem;
                    font-weight: 400;
                    color: #666666;
                    &:first-child,
                    &:last-child {
                        font-size: 1.2rem;
                        font-weight: 500;
                        color: #333333;
                    }
                    &:nth-child(2) {
                        margin: 0 2.6rem;
                    }
                }
            }
        }
    }
     :global {
        .am-picker-col-item-selected {
            font-size: 20px;
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值