学堂 学堂 学堂公众号手机端

小程序中的日期筛选器如何做的,代码是什么

lewis 1年前 (2024-04-29) 阅读数 14 #技术
这篇文章给大家分享的是“小程序中的日期筛选器如何做的,代码是什么”,对大家学习和理解有一定的参考价值和帮助,有这方面学习需要的朋友,接下来就跟随小编一起学习一下吧。

开发微信小程序过程中,有个需求需要用到日期时间筛选器,查看微信官方文档后,发现官方文档的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代码

<mp-half-screen-dialog show="{{ show }}" maskClosable="{{ true }}" closabled="{{ false }}" extClass="f-date-dialog" catchtouchmove="preventTouchMove" bindclose="bindclose">
 <view slot="desc" class="flex column full-width full-height">
  <view class="bd flex full-width">
   <!-- 日期 -->
   <view class="flex1 flex column align-items-center">
    <picker-view indicator-style="height: 50px;" mode="selector" value="{{ [dateIndex] }}" class="selector__picker" bindchange="dateChange">
     <picker-view-column>
      <view wx:for="{{ dateArr }}" wx:key="index" style="line-height: 50px" class="text-center {{ item.name.length < 10 ? 'h4' : 'h6' }}">{{ item.name }}</view>
     </picker-view-column>
    </picker-view>
   </view>
   <!-- 小时 -->
   <view class="flex1 flex column align-items-center">
    <picker-view indicator-style="height: 50px;" mode="selector" value="{{ [hourValue] }}" class="selector__picker" bindchange="hourChange">
     <picker-view-column>
      <view wx:for="{{ hourArr }}" wx:key="index" style="line-height: 50px" class="text-center">{{ item }}</view>
     </picker-view-column>
    </picker-view>
   </view>
   <!-- 分钟 -->
   <view class="flex1 flex column align-items-center">
    <picker-view indicator-style="height: 50px;" mode="selector" value="{{ [minValue] }}" class="selector__picker" bindchange="minChange">
     <picker-view-column>
      <view wx:for="{{ minArr }}" wx:key="index" style="line-height: 50px" class="text-center">{{ item }}</view>
     </picker-view-column>
    </picker-view>
   </view>
  </view>

  <view class="ft flex align-items-center justify-content-space-between">
   <button type="default" style="width:45%;height: 40px;" class="weui-btn" bindtap="bindclose">取消</button>
   <button type="primary" style="width:45%;height: 40px;margin-top:0" class="weui-btn" bindtap="handleSubmit">确定</button>
  </view>
 </view>
</mp-half-screen-dialog>

js代码

const utils = require('../../utils/util')

Component({
 options: {
  addGlobalClass: true
 },

 properties: {
  show: {
   type: Boolean,
   value: false,
   observer: '_showChange'
  },
  type: {
   type: String,
   value: 'center' // 类型:'left' -- 现在往前  'center' -- 往前&往后  'right' -- 现在往后
  },
  year: {
   type: Number,
   value: 1 // '时间区间{year}年' month不为undefined时该项失效
  },
  month: {
   type: [Number, String],
   value: 'undefined' // 'month' 不为undefined时 year失效
  }
 },

 data: {
  dateIndex: null,
  hourValue: '',
  minValue: '',
  dateArr: [],
  hourArr: [],
  minArr: [],

  activeTime: null // 抛出的时间戳
 },

 methods: {
  _showChange(e) {
   if (e) {
    this.handleDateData()
    this.initData()
   }
  },

  handleSubmit() {
   this.bindclose()
   this.triggerEvent('change', { value: this.data.activeTime })
  },

  initData() {
   const now = +new Date()
   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
   })
  },

  handleDateData() {
   const nowYear = new Date().getFullYear()
   let mins = []
   let 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())
   }

   dates = this.getDays(nowYear)

   this.setData({
    hourArr: hours,
    minArr: mins,
    dateArr: dates
   })
  },

  getDays(year) {
   let pre_days = []
   let now_days = []
   let aft_days = []

   if (this.data.month == 'undefined') {
    /** 按年处理 */
    // 判断类型
    if (this.data.type == 'left') {
     for (let a = this.data.year; a >= 1; a--) {
      pre_days.push(...this.getDaysByYear(year - a, true))
     }
    } else if (this.data.type == 'right') {
     for (let b = 1; b <= this.data.year; b++) {
      aft_days.push(...this.getDaysByYear(year + b, true))
     }
    } else {
     for (let a = this.data.year; a >= 1; a--) {
      pre_days.push(...this.getDaysByYear(year - a, true))
     }
     for (let b = 1; b <= this.data.year; b++) {
      aft_days.push(...this.getDaysByYear(year + b, true))
     }
    }
    now_days = this.getDaysByYear(year)
   } else {
    /** 按月处理 */
    now_days = this.getDaysByMonth(year, this.data.type)
   }

   return pre_days.concat(now_days.concat(aft_days))
  },

  getDaysByYear(year, isIncludeYear) {
   let days = []
   for (let k = 1; k < 13; k++) {
    let each_days = new Date(year, k, 0).getDate()
    for (let _k = 1; _k <= each_days; _k++) {
     let time = +new Date(`${year}-${k}-${_k}`)
     if (isIncludeYear) {
      days.push({ name: utils.formatTime(time, '{y}年{m}月{d}日周{a}'), value: time })
     } else {
      days.push({ name: utils.formatTime(time, '{m}月{d}日周{a}'), value: time })
     }
    }
   }
   return days
  },

  getDaysByMonth(year, type) {
   let days = []
   let nowMonth = new Date().getMonth() + 1

   // 当月份传负的或0时当成本月
   if (this.data.month > 0) {
    let months = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
    let pre_mons = []
    let aft_mons = []

    // 生成往前、往后的月份数组
    for (let k = 1; k <= this.data.month; k++) {
     let tmp_pre = months.indexOf(nowMonth) - k
     let tmp_aft = months.indexOf(nowMonth) + k
     pre_mons.unshift(months[tmp_pre < 0 ? 12 + tmp_pre : tmp_pre])
     aft_mons.push(months[tmp_aft > 12 ? tmp_aft - 12 : tmp_aft])
    }
    if (type != 'right') {
     // 往前的月份的日期
     pre_mons.forEach(v => {
      // 跨年
      let month_days = 0
      if (v > nowMonth) {
       month_days = new Date(year - 1, v, 0).getDate()
       for (let k = 1; k <= month_days; k++) {
        let time = +new Date(`${year - 1}-${v}-${k}`)
        days.push({ name: utils.formatTime(time, '{y}年{m}月{d}日周{a}'), value: time })
       }
      } else {
       month_days = new Date(year, v, 0).getDate()
       for (let k = 1; k <= month_days; k++) {
        let time = +new Date(`${year}-${v}-${k}`)
        days.push({ name: utils.formatTime(time, '{m}月{d}日周{a}'), value: time })
       }
      }
     })
    }

    // 本月的日期
    let month_days = new Date(year, nowMonth, 0).getDate()
    for (let k = 1; k <= month_days; k++) {
     let time = +new Date(`${year}-${nowMonth}-${k}`)
     days.push({ name: utils.formatTime(time, '{m}月{d}日周{a}'), value: time })
    }

    if (type != 'left') {
     // 往后的月份的日期
     aft_mons.forEach(_v => {
      // 跨年
      let month_days = 0
      if (_v < nowMonth) {
       month_days = new Date(year + 1, _v, 0).getDate()
       for (let k = 1; k <= month_days; k++) {
        let time = +new Date(`${year + 1}-${_v}-${k}`)
        days.push({ name: utils.formatTime(time, '{y}年{m}月{d}日周{a}'), value: time })
       }
      } else {
       month_days = new Date(year, _v, 0).getDate()
       for (let k = 1; k <= month_days; k++) {
        let time = +new Date(`${year}-${_v}-${k}`)
        days.push({ name: utils.formatTime(time, '{m}月{d}日周{a}'), value: time })
       }
      }
     })
    }
   } else {
    let month_days = new Date(year, nowMonth, 0).getDate()
    for (let k = 1; k <= month_days; k++) {
     let time = +new Date(`${year}-${nowMonth}-${k}`)
     days.push({ name: utils.formatTime(time, '{m}月{d}日周{a}'), value: time })
    }
   }

   return days
  },

  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
   })
  },

  preventTouchMove() {
   // 阻止半屏状态下 页面滑动
  }
 }
})

wxss代码

.selector__picker {
 width: 100%;
 height: 80%;
 margin-top: 20px;
 font-size: 24px;
}

上述代码中,js中引用的 utils 功能函数如下:

/**
* 日期格式化
*/
export function formatTime(time, cFormat) {
 if (arguments.length === 0) {
  return ''
 }
 const format = cFormat || '{y}-{m}-{d}'
 let date
 if (time === undefined || time === 0 || time === '') {
  return ''
 } else if (typeof time === 'object') {
  date = time
 } else {
  if (('' + time).length === 10) time = parseInt(time) * 1000
  date = new Date(time)
 }
 const formatObj = {
  y: date.getFullYear(),
  m: date.getMonth() + 1,
  d: date.getDate(),
  h: date.getHours(),
  i: date.getMinutes(),
  s: date.getSeconds(),
  a: date.getDay()
 }
 const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
  let value = formatObj[key]
  // Note: getDay() returns 0 on Sunday
  if (key === 'a') {
   return ['日', '一', '二', '三', '四', '五', '六'][value]
  }
  if (result.length > 0 && value < 10) {
   value = '0' + value
  }
  return value || 0
 })
 return time_str
}

另外wxml中使用的一些wxss公共样式就不提供了。


关于“小程序中的日期筛选器如何做的,代码是什么”就介绍到这了,如果大家觉得不错可以参考了解看看,如果想要了解更多,欢迎关注博信,小编每天都会为大家更新不同的知识。
版权声明

本文仅代表作者观点,不代表博信信息网立场。

热门