实现 日期加具体时间的微信小程序组件

项目:  Taro+react 微信小程序

1.需求:

  •  类似外卖提货的,左侧可选未来n天内的某一天提货, 右边可以选具体时+分
  •  限制某些时间段儿不能选

 

2. 实现:        

1. 首先: 检查Taro文档(基本与微信小程序一致),不支持这种 日期+时间的 ,so只能手撸一个

2. 微信的picker组件有这种多列模式,基于这个写

 

3. 这里的基本实现很简单,把每一列的数据铺进去就ok

3.难点在于

 

  1. 不可选当前时间之前的
    1. 如果选到当前时间之前的时间则把时间改成第二天的,或者改到当前时间
  2. 店铺有营业时间,不能选到 营业时间之内的时间
    1. 如果不在营业时间内则播到当天的最早营业时间
    2. 如果选择的就是当天,则播到当前时间

遇到的bug:

回播: 自动改选中的每列的值

选择的时间不在营业时间范围内时回播到当前时间,这里用到了多列选择器的 bindcolumnchange

第一次回拨的时候,把每列选中的值改成当前时间了,第二次选错的时候接着回播到当前时间,此时由于上一次的值也是当前时间, 每列选中的值未改变,则不生效,一开始一度以为是picker组件的问题,

所以这里列改变的时候,就直接先让列选中值改变了,再来判断需不需要回播

代码: 


import Taro, { Component } from '@tarojs/taro'
import { View, Text, Picker } from '@tarojs/components'
import '../../app.less'
import './index.less'

/** 
 * 选择 日期 + 时 + 分 的组件
 * 1. 拿到 yyyy/mm/dd hh:mm 该格式的时间返回
 * 2. 传一个参数, 限制时间的范围 -> 当天只能选择现在时间之后
 */

export default class diyPicker extends Component {
    state = {
        multiArray: 
            [
                ['今天', '明天', '后天'],
                Array.from({length: 24}, (_, i) => (i).toString().padStart(2, '0')),
                Array.from({length: 60}, (_, i) => (i).toString().padStart(2, '0'))
            ],
        multiIndex: [0, 0, 0],
        timeSel: true
    }
    static defaultProps = {
        isDisablePastTime: false, // 是否限制不选旧时间,默认不限制
        businessHours: ['00:00','23:59'], // 可选的时间范围,....邪门的营业时间 12:00-03:00, 传值少个0都不行哦
        dayNum: 8,
    }

    componentDidMount() {
        const multiArray = this.countDateFn(this.props.dayNum) // 计算第一列
        const nowHours = new Date().getHours()
        const nowMinute = new Date().getMinutes()
        this.setState({
            multiIndex: [0, nowHours, nowMinute],
            multiArray
        })
    }

    countDateFn(dayNum) {
        // dayNum 需要的时间天数 当天为1, 2为今天和明天
        // dateArr 最终返回日期数组
        const timeStampArr = [] // 最终返回时间戳数组
        const dayTime = 1000 * 60 * 60 * 24
        var weeks = ["日", "一", "二", "三", "四", "五", "六"]
        for (let i = 0; i < dayNum; i++) {
            const str =  Date.now() + dayTime * i
            timeStampArr.push(str)
        }
        // const dateArr = timeStampArr.map(x => new Date(x).getMonth() + 1 + '-' + new Date(x).getDate()) // 不加星期几
        const dateArr = timeStampArr.map(x => new Date(x).getMonth() + 1 + '-' + new Date(x).getDate() + `(周${weeks[new Date(x).getDay()]})`)
        let cloneMultiArray = JSON.parse(JSON.stringify(this.state.multiArray))
        cloneMultiArray[0] = dateArr
        return cloneMultiArray
    }


    onDateChange(e) {
        // console.log(' e.detail.value-----65',  e.detail.value);
        const {multiArray} = this.state
        const { businessHours } = this.props
        let startTime = businessHours[0]
        let endTime = businessHours[1]
        const nowHours = new Date().getHours()
        const nowMinute = new Date().getMinutes()
        let arr = e.detail.value
        // if (this.props.isDisablePastTime) { // 不能选过去的时间,已在选择每列的时候限制
        //     if (arr[0] == 0 && arr[1] < nowHours) {
        //         arr = [arr[0], nowHours, nowMinute]
        //     }
        //     if (arr[0] == 0 && arr[1] == nowHours && arr[2] < nowMinute) {
        //         arr = [arr[0], arr[1], nowMinute]
        //     }
        // }
        // 选择的时间不在营业范围时间,则改为当前时间
        const selectHour =  arr[1].toString().padStart(2, '0')
        const selectTimeStr = selectHour + ':' + arr[2].toString().padStart(2, '0') // 选择的时间
        if (endTime < startTime) { // 跨天的 例: 12:00-3:00(营业时间) ; 3点 -12点 不在营业时间
            if (startTime > selectTimeStr && selectTimeStr > endTime) { 
                arr = [0, nowHours, nowMinute]
                Taro.showToast({
                    title: `选择时间不在营业时间内,营业时间为${startTime}-次日${endTime}`,
                    icon: 'none',
                    duration: 2000
                })
            }
        }else {
            if (!(startTime <= selectTimeStr && selectTimeStr <= endTime)) { //  例: 9:00-20:00(营业时间)
                arr = [0, nowHours, nowMinute]
                Taro.showToast({
                    title: `选择时间不在营业时间内,营业时间为${startTime}-${endTime}`,
                    icon: 'none',
                    duration: 2000
                })
            }
        }
        const yearStr = new Date().getFullYear()
        const dateStr = multiArray[0][arr[0]].replace(/-/g, '/').replace(/\((.*)\)/, "")
        const hourStr = multiArray[1][arr[1]]
        const minuteStr = multiArray[2][arr[2]]
        const finallyTime = yearStr + '/' + dateStr + ' ' + hourStr + ':' + minuteStr + ':' + '00'
        // console.log('finallyTime', finallyTime);
        this.props.onCallBackFn(finallyTime)  // 返回给调用组件的方法- 时间示例(2024-1-23 01:07)
        let timeSel = !(arr[0] != 0 || ( arr[1] != nowHours || arr[2] != nowMinute))
        this.setState({
            multiIndex: arr,
            timeSel: timeSel
        })
    }

    onDateColumnChange(e) {
        const { multiArray , multiIndex} = this.state
        const { businessHours, isDisablePastTime } = this.props
        let startTime = businessHours[0]
        let endTime = businessHours[1]
        // console.log('修改的列为', e.detail.column, ',值为', e.detail.value, businessHours);
        let cloneMultiIndex = JSON.parse(JSON.stringify(multiIndex))
        let cloneMultiArray = JSON.parse(JSON.stringify(multiArray))
        cloneMultiIndex[e.detail.column] = e.detail.value;
        this.setState({
            multiIndex: cloneMultiIndex,
            multiArray: cloneMultiArray
        },() => {
            // 重新赋值,不然值未改变-选中的值不更新
            const nowHours = new Date().getHours()
            const nowMinute = new Date().getMinutes()
            if (this.props.isDisablePastTime) {
                switch (e.detail.column) {
                    case 0:
                        if (isDisablePastTime && (cloneMultiIndex[1] < nowHours || (cloneMultiIndex[1] == nowHours && e.detail.value < nowMinute))) { // 天数变成当天注意判断时间
                            cloneMultiIndex[1] = nowHours
                            cloneMultiIndex[2] = nowMinute
                        }
                        break
                    case 1:
                        if (isDisablePastTime && cloneMultiIndex[0] == 0  && e.detail.value < nowHours) { // 当天选过去时间则变成第二天
                            if (cloneMultiArray[0].length == 1) {
                                cloneMultiIndex[1] = nowHours
                                cloneMultiIndex[2] = nowMinute
                            }else {
                                cloneMultiIndex[0] = 1
                            }
                        }else {
                            // 限制营业时间内
                            const selectHour =  e.detail.value.toString().padStart(2, '0')
                            const selectTimeStr = selectHour + ':' + cloneMultiIndex[2].toString().padStart(2, '0') // 选择的时间
                            if (endTime < startTime) { // 跨天的 12:00-3:00(营业时间) ; 3点 -12点 不在营业时间
                                if (startTime > selectTimeStr && selectTimeStr > endTime) { // 前一段
                                    if (cloneMultiIndex[0] == 0) {
                                        cloneMultiIndex = [0, nowHours, nowMinute]
                                    }else {
                                        cloneMultiIndex = [cloneMultiIndex[0], Number(startTime.split(':')[0]), Number(startTime.split(':')[1])]
                                    }
                                    Taro.showToast({
                                        title: `选择时间不在营业时间内,营业时间为${startTime}-次日${endTime}`,
                                        icon: 'none',
                                        duration: 2000
                                    })
                                }
                            }else {
                                if (!(startTime <= selectTimeStr && selectTimeStr <= endTime)) { //  例: 9:00-20:00(营业时间)
                                    if (cloneMultiIndex[0] == 0) {
                                        cloneMultiIndex = [0, nowHours, nowMinute]
                                    }else {
                                        cloneMultiIndex = [cloneMultiIndex[0], Number(startTime.split(':')[0]), Number(startTime.split(':')[1])]
                                    }
                                    Taro.showToast({
                                        title: `选择时间不在营业时间内,营业时间为${startTime}-${endTime}`,
                                        icon: 'none',
                                        duration: 2000
                                    })
                                }
                            }
                        }
                        break;
                    case 2:
                        // 限制不能选当前时间之前
                        if (isDisablePastTime && cloneMultiIndex[0] == 0  && cloneMultiIndex[1] == nowHours && e.detail.value < nowMinute) {
                            if (cloneMultiArray[0].length == 1) {
                                cloneMultiIndex[2] = nowMinute
                            }else {
                                cloneMultiIndex[0] = 1
                            }
                        }else {
                            // 限制营业时间内
                            const selectMinute =  e.detail.value.toString().padStart(2, '0')
                            const selectMinuteStr = cloneMultiIndex[1].toString().padStart(2, '0') + ':' + selectMinute // 选择的时间
                            if (endTime < startTime) { // 跨天的 12:00-3:00(营业时间) ; 3点 -12点 不在营业时间
                                if (startTime > selectMinuteStr && selectMinuteStr > endTime) { // 前一段
                                    if (cloneMultiIndex[0] == 0) {
                                        cloneMultiIndex = [0, nowHours, nowMinute]
                                    }else {
                                        cloneMultiIndex = [cloneMultiIndex[0], Number(startTime.split(':')[0]), Number(startTime.split(':')[1])]
                                    }
                                    Taro.showToast({
                                        title: `选择时间不在营业时间内,营业时间为${startTime}-次日${endTime}`,
                                        icon: 'none',
                                        duration: 2000
                                        })
                                }
                            }else {
                                if (!(startTime <= selectMinuteStr && selectMinuteStr <= endTime)) { //  例: 9:00-20:00(营业时间)
                                    if (cloneMultiIndex[0] == 0) {
                                        cloneMultiIndex = [0, nowHours, nowMinute]
                                    }else {
                                        cloneMultiIndex = [cloneMultiIndex[0], Number(startTime.split(':')[0]), Number(startTime.split(':')[1])]
                                    }
                                    Taro.showToast({
                                        title: `选择时间不在营业时间内,营业时间为${startTime}-${endTime}`,
                                        icon: 'none',
                                        duration: 2000
                                    })
                                }
                            }
                        }
                        break;
                }
            }
              
            this.setState({
                multiIndex: cloneMultiIndex,
                multiArray: cloneMultiArray
            })
        })
    }

  render() {
    const { multiArray, multiIndex, timeSel} = this.state
    return <View>
        <Picker mode='multiSelector' onChange={this.onDateChange} onColumnChange={this.onDateColumnChange} range={multiArray} value={multiIndex}>
            <View className='picker c222 fs28 bold fsbc f1'>
                {timeSel ? '尽快提货 ' : ''}
                {multiArray[0][multiIndex[0]]} {multiArray[1][multiIndex[1]]}:{multiArray[2][multiIndex[2]]}
                <Text className='fs24 c999 iconfont'>&#xe632;</Text>
            </View>
        </Picker>
    </View>
  }
}

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
微信小程序提供了 `picker-view` 和 `picker` 组件,可以用于实现省市区三级联动的选择器。你可以利用这些组件来添地址。 下面是一个简单的添地址的示例代码: 1. 在小程序的 `wxml` 文件中添以下代码: ```html <!-- 省市区三级联动选择器 --> <view class="picker-container"> <picker-view class="picker-view" value="{{regionIndex}}" bindchange="bindRegionChange" indicator-style="height: 50px;"> <picker-view-column> <view wx:for="{{provinces}}" wx:key="index" class="picker"> {{item}} </view> </picker-view-column> <picker-view-column> <view wx:for="{{cities}}" wx:key="index" class="picker"> {{item}} </view> </picker-view-column> <picker-view-column> <view wx:for="{{areas}}" wx:key="index" class="picker"> {{item}} </view> </picker-view-column> </picker-view> </view> <!-- 收货人信息表单 --> <form class="address-form" bindsubmit="formSubmit"> <view class="form-group"> <view class="form-label">收货人:</view> <input class="form-input" type="text" name="name" placeholder="请输入收货人姓名" /> </view> <view class="form-group"> <view class="form-label">手机号码:</view> <input class="form-input" type="number" name="phone" placeholder="请输入手机号码" /> </view> <view class="form-group"> <view class="form-label">所在地区:</view> <input class="form-input" type="text" name="region" value="{{region}}" disabled /> </view> <view class="form-group"> <view class="form-label">详细地址:</view> <input class="form-input" type="text" name="address" placeholder="请输入详细地址" /> </view> <button class="form-btn" type="submit">保存地址</button> </form> ``` 2. 在小程序的 `js` 文件中添以下代码: ```javascript Page({ data: { provinces: [], // 省份列表 cities: [], // 城市列表 areas: [], // 区县列表 regionIndex: [0, 0, 0], // 省市区选择器的选择项 region: '', // 所在地区 }, // 页面载时获取省份列表 onLoad: function () { this.getProvinces(); }, // 获取省份列表 getProvinces: function () { let that = this; // 调用后台接口获取省份列表 wx.request({ url: 'https://example.com/getProvinces', success: function (res) { that.setData({ provinces: res.data, }); // 载省份列表后获取城市列表 that.getCities(res.data[0]); } }); }, // 获取城市列表 getCities: function (province) { let that = this; // 调用后台接口获取城市列表 wx.request({ url: 'https://example.com/getCities', data: { province: province }, success: function (res) { that.setData({ cities: res.data, }); // 载城市列表后获取区县列表 that.getAreas(that.data.provinces[that.data.regionIndex[0]], that.data.cities[that.data.regionIndex[1]]); } }); }, // 获取区县列表 getAreas: function (province, city) { let that = this; // 调用后台接口获取区县列表 wx.request({ url: 'https://example.com/getAreas', data: { province: province, city: city, }, success: function (res) { that.setData({ areas: res.data, region: province + city + res.data[0], }); } }); }, // 省市区选择器改变事件 bindRegionChange: function (e) { let that = this; that.setData({ regionIndex: e.detail.value, }); that.getAreas(that.data.provinces[e.detail.value[0]], that.data.cities[e.detail.value[1]]); }, // 表单提交事件 formSubmit: function (e) { console.log('form发生了submit事件,携带数据为:', e.detail.value); // 调用后台接口保存收货地址 wx.request({ url: 'https://example.com/saveAddress', data: e.detail.value, success: function (res) { console.log(res.data); } }); }, }); ``` 在这个示例中,我们使用 `picker-view` 组件实现了省市区三级联动的选择器,用户选择了所在地区之后,输入框会自动填充所选的省市区信息。用户填写完所有信息之后,点击保存地址按钮会触发表单提交事件,将表单的数据提交给后台接口保存到数据库中。 需要注意的是,示例中的后台接口和数据库都需要开发者自己搭建和维护。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值