[前端] 微信小程序实现日期时间筛选器

2192 0
Honkers 2022-10-21 15:42:12 | 显示全部楼层 |阅读模式
开发微信小程序过程中,有个需求需要用到日期时间筛选器,查看微信官方文档后,发现官方文档的picker筛选器只能单独支持日期或者是时间,所以为了实现需求自己参考企业微信封装了个日期时间筛选器组件。
原理

筛选器的实现,我参考的是小程序官方方式,通过半屏弹窗(mp-half-screen-dialog)结合picker_view进行日期、时间的选择,最终在选择时间后,通过事件触发返回一个change事件,其中参数值为毫秒级时间戳。
实现

1.弹窗的显隐:
在组件的 properties 中传入一个 show 字段,用于控制弹窗的显隐;默认值为 false
2.筛选器类型:
为了更好的兼容性,提供一个 type 字段,用于控制筛选器的所支持 可选择日期 的走向(往前、往后、前后都支持);默认值为 center(前后都支持)。
3.时间区间(年):
year 字段用于控制筛选器的年维度时间区间范围;默认值为 1。
4.时间区间(月):
month 字段用于控制筛选器的月维度时间区间范围。默认值为 ‘undefined’****(声明’month’ 不为undefined时 year失效)。
具体思路:整体思路是监听弹窗的显隐(show),当弹窗显示时,获取对应配置项(类型、年、月)计算对应筛选器的范围,并初始化默认日期时间为当前年月日时分
以下是效果图以及具体代码实现:




wxml代码
  1. <mp-half-screen-dialog show="{{ show }}" maskClosable="{{ true }}" closabled="{{ false }}" extClass="f-date-dialog" catchtouchmove="preventTouchMove" bindclose="bindclose">
  2. <view slot="desc" class="flex column full-width full-height">
  3.   <view class="bd flex full-width">
  4.    <!-- 日期 -->
  5.    <view class="flex1 flex column align-items-center">
  6.     <picker-view indicator-style="height: 50px;" mode="selector" value="{{ [dateIndex] }}" class="selector__picker" bindchange="dateChange">
  7.      <picker-view-column>
  8.       <view wx:for="{{ dateArr }}" wx:key="index" style="line-height: 50px" class="text-center {{ item.name.length < 10 ? 'h4' : 'h6' }}">{{ item.name }}</view>
  9.      </picker-view-column>
  10.     </picker-view>
  11.    </view>
  12.    <!-- 小时 -->
  13.    <view class="flex1 flex column align-items-center">
  14.     <picker-view indicator-style="height: 50px;" mode="selector" value="{{ [hourValue] }}" class="selector__picker" bindchange="hourChange">
  15.      <picker-view-column>
  16.       <view wx:for="{{ hourArr }}" wx:key="index" style="line-height: 50px" class="text-center">{{ item }}</view>
  17.      </picker-view-column>
  18.     </picker-view>
  19.    </view>
  20.    <!-- 分钟 -->
  21.    <view class="flex1 flex column align-items-center">
  22.     <picker-view indicator-style="height: 50px;" mode="selector" value="{{ [minValue] }}" class="selector__picker" bindchange="minChange">
  23.      <picker-view-column>
  24.       <view wx:for="{{ minArr }}" wx:key="index" style="line-height: 50px" class="text-center">{{ item }}</view>
  25.      </picker-view-column>
  26.     </picker-view>
  27.    </view>
  28.   </view>
  29.   <view class="ft flex align-items-center justify-content-space-between">
  30.    <button type="default" style="width:45%;height: 40px;" class="weui-btn" bindtap="bindclose">取消</button>
  31.    <button type="primary" style="width:45%;height: 40px;margin-top:0" class="weui-btn" bindtap="handleSubmit">确定</button>
  32.   </view>
  33. </view>
  34. </mp-half-screen-dialog>
复制代码
js代码
  1. const utils = require('../../utils/util')
  2. Component({
  3. options: {
  4.   addGlobalClass: true
  5. },
  6. properties: {
  7.   show: {
  8.    type: Boolean,
  9.    value: false,
  10.    observer: '_showChange'
  11.   },
  12.   type: {
  13.    type: String,
  14.    value: 'center' // 类型:'left' -- 现在往前  'center' -- 往前&往后  'right' -- 现在往后
  15.   },
  16.   year: {
  17.    type: Number,
  18.    value: 1 // '时间区间{year}年' month不为undefined时该项失效
  19.   },
  20.   month: {
  21.    type: [Number, String],
  22.    value: 'undefined' // 'month' 不为undefined时 year失效
  23.   }
  24. },
  25. data: {
  26.   dateIndex: null,
  27.   hourValue: '',
  28.   minValue: '',
  29.   dateArr: [],
  30.   hourArr: [],
  31.   minArr: [],
  32.   activeTime: null // 抛出的时间戳
  33. },
  34. methods: {
  35.   _showChange(e) {
  36.    if (e) {
  37.     this.handleDateData()
  38.     this.initData()
  39.    }
  40.   },
  41.   handleSubmit() {
  42.    this.bindclose()
  43.    this.triggerEvent('change', { value: this.data.activeTime })
  44.   },
  45.   initData() {
  46.    const now = +new Date()
  47.    const index = this.data.dateArr.map(v => v.name).indexOf(utils.formatTime(now, '{m}月{d}日周{a}'))
  48.    let tmp = this.data.dateArr
  49.    tmp[index].name = '今天'
  50.    this.setData({
  51.     dateIndex: index,
  52.     hourValue: utils.formatTime(now, '{h}'),
  53.     minValue: utils.formatTime(now, '{i}'),
  54.     dateArr: tmp,
  55.     activeTime: now
  56.    })
  57.   },
  58.   handleDateData() {
  59.    const nowYear = new Date().getFullYear()
  60.    let mins = []
  61.    let hours = []
  62.    let dates = []
  63.    // 获取小时、分钟数组
  64.    for (let i = 0; i < 60; i++) {
  65.     mins.push(i.toString().length < 2 ? '0' + i : i.toString())
  66.    }
  67.    for (let j = 0; j < 24; j++) {
  68.     hours.push(j.toString().length < 2 ? '0' + j : j.toString())
  69.    }
  70.    dates = this.getDays(nowYear)
  71.    this.setData({
  72.     hourArr: hours,
  73.     minArr: mins,
  74.     dateArr: dates
  75.    })
  76.   },
  77.   getDays(year) {
  78.    let pre_days = []
  79.    let now_days = []
  80.    let aft_days = []
  81.    if (this.data.month == 'undefined') {
  82.     /** 按年处理 */
  83.     // 判断类型
  84.     if (this.data.type == 'left') {
  85.      for (let a = this.data.year; a >= 1; a--) {
  86.       pre_days.push(...this.getDaysByYear(year - a, true))
  87.      }
  88.     } else if (this.data.type == 'right') {
  89.      for (let b = 1; b <= this.data.year; b++) {
  90.       aft_days.push(...this.getDaysByYear(year + b, true))
  91.      }
  92.     } else {
  93.      for (let a = this.data.year; a >= 1; a--) {
  94.       pre_days.push(...this.getDaysByYear(year - a, true))
  95.      }
  96.      for (let b = 1; b <= this.data.year; b++) {
  97.       aft_days.push(...this.getDaysByYear(year + b, true))
  98.      }
  99.     }
  100.     now_days = this.getDaysByYear(year)
  101.    } else {
  102.     /** 按月处理 */
  103.     now_days = this.getDaysByMonth(year, this.data.type)
  104.    }
  105.    return pre_days.concat(now_days.concat(aft_days))
  106.   },
  107.   getDaysByYear(year, isIncludeYear) {
  108.    let days = []
  109.    for (let k = 1; k < 13; k++) {
  110.     let each_days = new Date(year, k, 0).getDate()
  111.     for (let _k = 1; _k <= each_days; _k++) {
  112.      let time = +new Date(`${year}-${k}-${_k}`)
  113.      if (isIncludeYear) {
  114.       days.push({ name: utils.formatTime(time, '{y}年{m}月{d}日周{a}'), value: time })
  115.      } else {
  116.       days.push({ name: utils.formatTime(time, '{m}月{d}日周{a}'), value: time })
  117.      }
  118.     }
  119.    }
  120.    return days
  121.   },
  122.   getDaysByMonth(year, type) {
  123.    let days = []
  124.    let nowMonth = new Date().getMonth() + 1
  125.    // 当月份传负的或0时当成本月
  126.    if (this.data.month > 0) {
  127.     let months = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
  128.     let pre_mons = []
  129.     let aft_mons = []
  130.     // 生成往前、往后的月份数组
  131.     for (let k = 1; k <= this.data.month; k++) {
  132.      let tmp_pre = months.indexOf(nowMonth) - k
  133.      let tmp_aft = months.indexOf(nowMonth) + k
  134.      pre_mons.unshift(months[tmp_pre < 0 ? 12 + tmp_pre : tmp_pre])
  135.      aft_mons.push(months[tmp_aft > 12 ? tmp_aft - 12 : tmp_aft])
  136.     }
  137.     if (type != 'right') {
  138.      // 往前的月份的日期
  139.      pre_mons.forEach(v => {
  140.       // 跨年
  141.       let month_days = 0
  142.       if (v > nowMonth) {
  143.        month_days = new Date(year - 1, v, 0).getDate()
  144.        for (let k = 1; k <= month_days; k++) {
  145.         let time = +new Date(`${year - 1}-${v}-${k}`)
  146.         days.push({ name: utils.formatTime(time, '{y}年{m}月{d}日周{a}'), value: time })
  147.        }
  148.       } else {
  149.        month_days = new Date(year, v, 0).getDate()
  150.        for (let k = 1; k <= month_days; k++) {
  151.         let time = +new Date(`${year}-${v}-${k}`)
  152.         days.push({ name: utils.formatTime(time, '{m}月{d}日周{a}'), value: time })
  153.        }
  154.       }
  155.      })
  156.     }
  157.     // 本月的日期
  158.     let month_days = new Date(year, nowMonth, 0).getDate()
  159.     for (let k = 1; k <= month_days; k++) {
  160.      let time = +new Date(`${year}-${nowMonth}-${k}`)
  161.      days.push({ name: utils.formatTime(time, '{m}月{d}日周{a}'), value: time })
  162.     }
  163.     if (type != 'left') {
  164.      // 往后的月份的日期
  165.      aft_mons.forEach(_v => {
  166.       // 跨年
  167.       let month_days = 0
  168.       if (_v < nowMonth) {
  169.        month_days = new Date(year + 1, _v, 0).getDate()
  170.        for (let k = 1; k <= month_days; k++) {
  171.         let time = +new Date(`${year + 1}-${_v}-${k}`)
  172.         days.push({ name: utils.formatTime(time, '{y}年{m}月{d}日周{a}'), value: time })
  173.        }
  174.       } else {
  175.        month_days = new Date(year, _v, 0).getDate()
  176.        for (let k = 1; k <= month_days; k++) {
  177.         let time = +new Date(`${year}-${_v}-${k}`)
  178.         days.push({ name: utils.formatTime(time, '{m}月{d}日周{a}'), alue: time })
  179.        }
  180.       }
  181.      })
  182.     }
  183.    } else {
  184.     let month_days = new Date(year, nowMonth, 0).getDate()
  185.     for (let k = 1; k <= month_days; k++) {
  186.      let time = +new Date(`${year}-${nowMonth}-${k}`)
  187.      days.push({ name: utils.formatTime(time, '{m}月{d}日周{a}'), value: time })
  188.     }
  189.    }
  190.    return days
  191.   },
  192.   dateChange(e) {
  193.    const day = this.data.dateArr[e.detail.value[0]]
  194.    let time = day.value + (Number(this.data.hourValue) * 3600 + Number(this.data.minValue) * 60) * 1000
  195.    this.setData({
  196.     dateIndex: e.detail.value[0],
  197.     activeTime: time
  198.    })
  199.   },
  200.   hourChange(e) {
  201.    const hour = Number(this.data.hourArr[e.detail.value[0]])
  202.    let time = this.data.dateArr[this.data.dateIndex].value + (hour * 3600 + Number(this.data.minValue) * 60) * 1000
  203.    this.setData({
  204.     hourValue: this.data.hourArr[e.detail.value[0]],
  205.     activeTime: time
  206.    })
  207.   },
  208.   minChange(e) {
  209.    const min = Number(this.data.minArr[e.detail.value[0]])
  210.    let time = this.data.dateArr[this.data.dateIndex].value + (Number(this.data.hourValue) * 3600 + min * 60) * 1000
  211.    this.setData({
  212.     minValue: this.data.minArr[e.detail.value[0]],
  213.     activeTime: time
  214.    })
  215.   },
  216.   bindclose() {
  217.    this.setData({
  218.     show: false
  219.    })
  220.   },
  221.   preventTouchMove() {
  222.    // 阻止半屏状态下 页面滑动
  223.   }
  224. }
  225. })
复制代码
wxss代码
  1. .selector__picker {
  2. width: 100%;
  3. height: 80%;
  4. margin-top: 20px;
  5. font-size: 24px;
  6. }
复制代码
上述代码中,js中引用的 utils 功能函数如下:
  1. /**
  2. * 日期格式化
  3. */
  4. export function formatTime(time, cFormat) {
  5. if (arguments.length === 0) {
  6.   return ''
  7. }
  8. const format = cFormat || '{y}-{m}-{d}'
  9. let date
  10. if (time === undefined || time === 0 || time === '') {
  11.   return ''
  12. } else if (typeof time === 'object') {
  13.   date = time
  14. } else {
  15.   if (('' + time).length === 10) time = parseInt(time) * 1000
  16.   date = new Date(time)
  17. }
  18. const formatObj = {
  19.   y: date.getFullYear(),
  20.   m: date.getMonth() + 1,
  21.   d: date.getDate(),
  22.   h: date.getHours(),
  23.   i: date.getMinutes(),
  24.   s: date.getSeconds(),
  25.   a: date.getDay()
  26. }
  27. const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
  28.   let value = formatObj[key]
  29.   // Note: getDay() returns 0 on Sunday
  30.   if (key === 'a') {
  31.    return ['日', '一', '二', '三', '四', '五', '六'][value]
  32.   }
  33.   if (result.length > 0 && value < 10) {
  34.    value = '0' + value
  35.   }
  36.   return value || 0
  37. })
  38. return time_str
  39. }
复制代码
另外wxml中使用的一些wxss公共样式就不提供了。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持中国红客联盟。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Honkers

荣誉红客

关注
  • 4010
    主题
  • 36
    粉丝
  • 0
    关注
这家伙很懒,什么都没留下!

中国红客联盟公众号

联系站长QQ:5520533

admin@chnhonker.com
Copyright © 2001-2025 Discuz Team. Powered by Discuz! X3.5 ( 粤ICP备13060014号 )|天天打卡 本站已运行