赞
踩
开发微信小程序过程中,有个需求需要用到日期时间筛选器,查看微信官方文档后,发现官方文档的picker筛选器只能单独支持日期或者是时间,所以为了实现需求自己参考企业微信封装了个日期时间筛选器组件。
写在前面!!! 由于较多朋友有源码需求,我抽了个时间整理了一下代码,并对一年前的代码进行了升级和优化,并放在我github上,有需要的自取:微信小程序日期时间选择器
筛选器的实现,我参考的是小程序官方方式,通过半屏弹窗(mp-half-screen-dialog)结合picker_view进行日期、时间的选择,最终在选择时间后,通过事件触发返回一个change事件,其中参数值为毫秒级时间戳。需要注意的是,由于组件样式需要,对mp-half-screen-dialog做了一定的样式改造,并且为了不影响全局的mp-half-screen-dialog样式,使用指定的extClass进行样式控制,样式具体实现代码在app.wxss中。
1.弹窗的显隐:
在组件的 properties 中传入一个 show 字段,用于控制弹窗的显隐;默认值为 false。
2.开始时间,时间戳:
毫秒级时间戳,非必填,默认为,距现在一年前的时间。
3.结束时间,时间戳:
毫秒级时间戳,非必填,默认为,距现在一年后的时间。
具体思路:整体思路是监听弹窗的显隐(show),当弹窗显示时,获取对应配置项(类型、年、月)计算对应筛选器的范围,并初始化默认日期时间为当前年月日时分。
以下是效果图以及具体代码实现:
<!--components/date-time-picker.wxml--> <mp-half-screen-dialog show="{{ show }}" maskClosable="{{ false }}" closabled="{{ false }}" extClass="date-time-dialog" catchtouchmove="preventTouchMove" bindclose="bindclose"> <view slot="desc" class="date-time-container"> <view class="date-time-body"> <!-- 日期 --> <view class="selector-panel selector-panel-date"> <picker-view indicator-style="height: 55px;" mode="selector" value="{{ [dateIndex] }}" class="selector-picker" bindchange="dateChange" bindpickstart="bindpickstart" bindpickend="bindpickend"> <picker-view-column> <view wx:for="{{ dateArr }}" wx:key="index" class="selector-item selector-item-date">{{ item.name }}</view> </picker-view-column> </picker-view> </view> <!-- 小时 --> <view class="selector-panel"> <picker-view indicator-style="height: 55px;" mode="selector" value="{{ [hourValue] }}" class="selector-picker" bindchange="hourChange" bindpickstart="bindpickstart" bindpickend="bindpickend"> <picker-view-column> <view wx:for="{{ hourArr }}" wx:key="index" class="selector-item">{{ item }}</view> </picker-view-column> </picker-view> </view> <!-- 分钟 --> <view class="selector-panel"> <picker-view indicator-style="height: 55px;" mode="selector" value="{{ [minValue] }}" class="selector-picker" bindchange="minChange" bindpickstart="bindpickstart" bindpickend="bindpickend"> <picker-view-column> <view wx:for="{{ minArr }}" wx:key="index" class="selector-item">{{ item }}</view> </picker-view-column> </picker-view> </view> </view> <view class="date-time-oper"> <button type="default" class="weui-btn oper-btn" bindtap="bindclose">取消</button> <button type="primary" class="weui-btn oper-btn" bindtap="handleSubmit" disabled="{{ disabled }}">确定</button> </view> </view> </mp-half-screen-dialog>
const utils = require('../utils/util') const yearTimestamp = 365 * 24 * 60 * 60 * 1000 // 一年 Component({ /** * 组件的属性列表 */ properties: { show: { type: Boolean, value: false, observer: '_showChange' }, // 开始时间,时间戳 startTime: { type: Number, value: +new Date() - yearTimestamp // 默认,一年前 }, // 结束时间,时间戳 endTime: { type: Number, value: +new Date() + yearTimestamp // 默认,一年后 } }, /** * 组件的初始数据 */ data: { disabled: false, // button disable态 dateIndex: null, hourValue: '', minValue: '', dateArr: [], hourArr: [], minArr: [], activeTime: null // 抛出的时间戳 }, /** * 组件的方法列表 */ methods: { _showChange (e) { if (e) { this.getDateTimeData() this.initData() } }, handleSubmit () { this.bindclose() this.triggerEvent('change', { value: this.data.activeTime }) }, /** * 处理日期时间初始值 */ initData () { if (!this.data.activeTime) { const now = +new Date() if (now >= this.data.startTime && now <= this.data.endTime) { const index = this.data.dateArr.map(v => v.name).indexOf(utils.formatTime(now, '{m}月{d}日周{a}')) let tmp = this.data.dateArr tmp[index].name = '今天' this.setData({ dateIndex: index, hourValue: utils.formatTime(now, '{h}'), minValue: utils.formatTime(now, '{i}'), dateArr: tmp, activeTime: now }) } } }, /** * 获取日期时间数据,思路:获取固定的小时、分钟数组,将开始时间、结束时间进行年月天对比,取其差值,从而形成对应日期数组 */ getDateTimeData () { const mins = [] const hours = [] let dates = [] // 获取小时、分钟数组 for (let i = 0; i < 60; i++) { mins.push(i.toString().length < 2 ? '0' + i : i.toString()) } for (let j = 0; j < 24; j++) { hours.push(j.toString().length < 2 ? '0' + j : j.toString()) } // 开始时间需小于结束时间 if (this.data.startTime >= this.data.endTime) { console.log('error_params_not_valid') return } // 获取日期数组 dates = this.getDateData() this.setData({ hourArr: hours, minArr: mins, dateArr: dates }) }, getDateData () { const startDate = new Date(this.data.startTime) const endDate = new Date(this.data.endTime) const nowYear = new Date().getFullYear() const startYear = startDate.getFullYear() const endYear = endDate.getFullYear() const startMonth = startDate.getMonth() const endMonth = endDate.getMonth() const startDay = startDate.getDate() const endDay = endDate.getDate() const dateArr = [] // 处理逻辑:判断年限是否相同;若同年则判断是否同月,同月则直接添加日期;不同月则从开始时间月份处理,同时处理月日边界问题;以此类推... let time = 0 // 同年 if (startYear === endYear) { // 同月 if (startMonth === endMonth) { for (let day = startDay; day <= endDay; day++) { time = new Date(startYear, startMonth, day) dateArr.push({ name: startYear === nowYear ? utils.formatTime(time, '{m}月{d}日周{a}') : utils.formatTime(time, '{y}年{m}月{d}日周{a}'), value: time }) } } else { // 不同月 let tmpDay = startDay let lastMonth = endMonth for (let month = startMonth; month <= lastMonth; month++) { // 默认获取的月份方法得到月份值是0-11,该方法获取天数的月份值是1-12 const days = month === lastMonth ? endDay : new Date(startYear, month + 1, 0).getDate() for (let day = tmpDay; day <= days; day++) { time = new Date(startYear, month, day) dateArr.push({ name: startYear === nowYear ? utils.formatTime(time, '{m}月{d}日周{a}') : utils.formatTime(time, '{y}年{m}月{d}日周{a}'), value: time }) // 处理边界(日) day === days && (tmpDay = 1) } } } } else { // 不同年 let tmpDay = startDay let tmpMonth = startMonth let lastMonth = 11 for (let year = startYear; year <= endYear; year++) { for (let month = tmpMonth; month <= lastMonth; month++) { // 默认获取的月份方法得到月份值是0-11,该方法获取天数的月份值是1-12 const days = (month === lastMonth && year === endYear) ? endDay : new Date(startYear, month + 1, 0).getDate() for (let day = tmpDay; day <= days; day++) { time = +new Date(year, month, day) dateArr.push({ name: year === nowYear ? utils.formatTime(time, '{m}月{d}日周{a}') : utils.formatTime(time, '{y}年{m}月{d}日周{a}'), value: time }) // 处理边界(日) day === days && (tmpDay = 1) } // 处理边界(月) month === lastMonth && (tmpMonth = 0) month === lastMonth && year === endYear - 1 && (lastMonth = endMonth) } } } return dateArr }, dateChange (e) { const day = this.data.dateArr[e.detail.value[0]] let time = day.value + (Number(this.data.hourValue) * 3600 + Number(this.data.minValue) * 60) * 1000 this.setData({ dateIndex: e.detail.value[0], activeTime: time }) }, hourChange (e) { const hour = Number(this.data.hourArr[e.detail.value[0]]) let time = this.data.dateArr[this.data.dateIndex].value + (hour * 3600 + Number(this.data.minValue) * 60) * 1000 this.setData({ hourValue: this.data.hourArr[e.detail.value[0]], activeTime: time }) }, minChange (e) { const min = Number(this.data.minArr[e.detail.value[0]]) let time = this.data.dateArr[this.data.dateIndex].value + (Number(this.data.hourValue) * 3600 + min * 60) * 1000 this.setData({ minValue: this.data.minArr[e.detail.value[0]], activeTime: time }) }, bindclose () { this.setData({ show: false }) }, bindpickstart () { this.setData({ disabled: true }) }, bindpickend () { this.setData({ disabled: false }) }, preventTouchMove () { // 阻止半屏状态下 页面滑动 } } })
.date-time-container { min-height: 350px !important; display: flex; flex-direction: column; } .date-time-body { width: 100% !important; display: flex; flex: auto; } .date-time-oper { flex: none; display: flex; justify-content: space-between; align-items: center; } .selector-panel { width: 80px; display: flex; align-items: center; } .selector-panel-date { flex: auto; } .selector-picker { width: 100%; height: 80%; font-size: 24px; } .selector-item { line-height: 50px !important; text-align: center; } .selector-item-date{ font-size: 16px; } .oper-btn { width: 45% !important; height: 40px !important; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。