代码直接复制就可以,简单易懂,没有其他副作用。只要按组件接收的格式传入相对应格式即可,也可以自己改造~
用到前端语言: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,选择了则为选择的时间'}
效果图:
页面代码
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;
}
}
}