使用antd-mobile的PickerView实现一个跨天时间选择器

需求逻辑

  1. 今天到明天预约时间范围是下一分钟开始往后的24小时
  2. 切换每列数据时,其他列对应的数据要自动切换到合适的范围
  3. 每次打开预约开关时,预约的数据列表及时更新
  4. antd-mobile的PickerView组件有个bug:在onChange事件中切换数据源后,有时可以自动再次触发onChange以获取正确的值,但有时不会。所以这里在每次切换数据源后,根据情况手动获取picker的值以进行修正

完成效果如下:

在这里插入图片描述
在这里插入图片描述

组件代码

import { useState, useEffect } from 'react'
import { PickerView, Switch } from 'antd-mobile'

let day = [{
    label: '今天',
    value: '今天',
}, {
    label: '明天',
    value: '明天',
}]

export default function AppointmentPickerView({ setTime, time, setOpen, open, getInitTime }) {

    const [dataTodayH, setDataTodayH] = useState([])
    const [dataTomorrowH, setDataTomorrowH] = useState([])
    const [dataTodayFirstM, setDataTodayFirstM] = useState([])
    const [dataTomorrowLastM, setDataTomorrowLastM] = useState([])
    const [dataM60, setDataM60] = useState([])
    const [sourceData, setSourceData] = useState([])
    const [isNow23H59M, setIsNow23H59M] = useState(false)

    useEffect(() => {
        // const now = new Date(2010,1,1,23,1,1,1)
        const now = new Date()
        let nowH = now.getHours()
        let nowM = now.getMinutes()
        getInitTime(now)
        let isNow59M = nowM === 59
        setIsNow23H59M(isNow59M && nowH === 23)
        let min, max

        // 生成picker每列数据的通用方法
        const getPickerColData = (min, max, step = 1) => {
            let [arr, i] = [[], min]
            while (i <= max) {
                arr.push({
                    label: i,
                    value: i,
                })
                i += step
            }
            return arr
        }
        // 今天小时
        min = isNow59M ? nowH + 1 : nowH
        setDataTodayH(getPickerColData(min, 23))
        // 明天小时
        // max = isNow59M ? nowH - 1 : nowH
        max = isNow23H59M ? 23 : nowH
        setDataTomorrowH(getPickerColData(0, max))
        // 今天第一个小时的分钟
        min = isNow59M ? 0 : nowM + 1 // 判断进位
        setDataTodayFirstM(getPickerColData(min, 59))
        // 明天最后一个小时的分钟
        max = isNow59M ? 59 : nowM
        setDataTomorrowLastM(getPickerColData(0, max))
        // 60分钟
        setDataM60(getPickerColData(0, 59))
    }, [open])

    // 设置数据源
    useEffect(() => {
        if (isNow23H59M) {
            setSourceData([[day[1]], dataTomorrowH, dataM60])
            return
        }
        setSourceData([day, dataTodayH, dataTodayFirstM])
    }, [day, dataTodayH, dataTodayFirstM])

    // 滑动选择事件
    const onPickerChange = (v, index) => {

        // antd-mobile的PickerView组件有个bug:
        // 在onChange事件中切换数据源后,有时可以自动再次触发onChange以获取正确的值,但有时不会。
        // 所以这里在每次切换数据源后,根据情况手动获取picker的值以进行修正
        const tomorrowLastH = dataTomorrowH[dataTomorrowH.length - 1].value
        if (index === 0) { // 选择第一列今天明天
            let dataH = dataTodayH
            let dataM = dataM60
            if (v[0] === '今天') {
                dataM = dataTodayFirstM
                v[1] = dataTodayH[0].value
                v[2] = dataTodayFirstM[0].value
            } else { // 选择明天
                dataH = dataTomorrowH
                if (dataTodayH[0].value !== tomorrowLastH) { // 整点时今天的小时数明天没有
                    v[1] = 0
                }
                if (v[1] === tomorrowLastH) { // 明天仅剩最后一个小时
                    dataM = dataTomorrowLastM
                    v[2] = 0
                }
            }
            setSourceData(data => {
                data[1] = dataH
                data[2] = dataM
                return data
            })
        } else if (index === 1) { // 选择第二列小时
            let dataM = dataM60
            if (v[0] === '今天' && v[1] === dataTodayH[0].value) { // 今天第一个小时
                dataM = dataTodayFirstM
            }
            if (v[0] === '明天' && v[1] === tomorrowLastH) { // 明天最后一个小时
                dataM = dataTomorrowLastM
            }
            setSourceData(data => {
                data[2] = dataM
                return data
            })
        }
        console.log('~~v', v)
        setTime(v)
    }

    // 预约开关
    const onSwitchChange = v => {
        setOpen(v)
        if (!v) return

        if (isNow23H59M) {
            setTime(['明天', 0, 0])
            return
        }
        setTime(['今天', dataTodayH[0].value, dataTodayFirstM[0].value])
    }

    return <>
        <div className='itemForPicker' >
            <span className='content'>预约 (完成时间)</span>
            <Switch checked={open} onChange={onSwitchChange} />
        </div>
        {open &&
            <div className="openAppointmentInner">
                <PickerView cascade={false} data={sourceData} value={time} onChange={onPickerChange} />
            </div>
        }
    </>
}

组件引用

<AppointmentPickerView
    setTime={setAppointmentTime} // 设置时间的回调
    time={appointmentTime} // 时间的值
    setOpen={setAppointmentOpenChangeBg} // 设置预约开关的回调
    open={appointmentOpen} // 预约开关的值
    getInitTime={setAppointmentInitTime} // 预约组件参考的时间,在编辑页停留时间过长判断是否跨过0点时用
/>

样式代码

.openAppointmentInner {
    .am-picker {
        position: relative;
        &:before {
            content: ':';
            position: absolute;
            left: 67%;
            transform: translate(-50%, -50%);
            font-size: 1rem;
        }
    }
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
下拉选择可以使用 Ant Design Mobile 中的 Picker 组件来实现。以下是一个简单的例子: ```jsx import React, { useState } from 'react'; import { Picker } from 'antd-mobile'; function SelectExample() { const [value, setValue] = useState(null); const data = [ { label: '北京', value: 'beijing' }, { label: '上海', value: 'shanghai' }, { label: '广州', value: 'guangzhou' }, { label: '深圳', value: 'shenzhen' }, ]; return ( <Picker data={data} value={value} onChange={setValue} cols={1} className="forss" > <div>请选择城市</div> </Picker> ); } export default SelectExample; ``` 在这个例子中,我们首先引入了 `Picker` 组件,然后定义了一个 `SelectExample` 组件。在 `SelectExample` 组件中,我们使用React 的 `useState` 钩子来保存选择的值。然后,我们定义了一个数据数组 `data`,其中包含了可选项的标签和值。接着,在 `Picker` 组件中,我们传入了 `data`、`value`、`onChange`、`cols` 和 `className` 等属性。其中,`data` 表示可选项的数据,`value` 和 `onChange` 则分别表示当前选中的值和选择后的回调函数,`cols` 表示选择器的列数,`className` 则表示选择器的样式。最后,我们在 `Picker` 组件中还传入了一个 `div` 元素,用来显示选择器的提示信息。 当用户点击选择器时,会弹出一个下拉框,用户可以在其中选择一个选项。选择后,会自动更新 `value` 的值,并且触发 `onChange` 回调函数。我们可以根据 `value` 的值来进行后续操作。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值