欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

小程序修改时间选择器组件

程序员文章站 2024-01-22 19:35:10
...

目的:
在实际开发中,小程序提供的picker时间选择器无法修改样式,这可能与项目整体的风格不一致,因此借助小程序picker-view实现自定义样式的时间选择器
功能:
支持默认时间,初始值是当天,根据选择的不同年月日限制可选值(因为大小月平年闰年天数不一样)

readme

Props
defaultValue:string(2019-10-15)
默认值:当前时间
Events

cancel:Function
说明:取消时触发
参数:null

confirm:Function
说明:确定时触发
参数:event.detail选中的时间

直接将下面代码复制即可直接使用
js

// components/date_time_picker/index.js
const years = []
const months = []
const days = []
const date = new Date
const currentYear = date.getFullYear()
const currentMonth = date.getMonth() + 1
const currentDay = date.getDate()

// 根据年和月获取当月天数
function getDayNum(year, month) {
  return new Date(year, month, 0).getDate()
}

for (let i = currentYear; i <= 2099; i++) {
  years.push(i)
}

for (let i = currentMonth; i <= 12; i++) {
  months.push(i)
}

for (let i = currentDay; i <= getDayNum(currentYear, currentMonth); i++) {
  days.push(i)
}

let selectedYear = currentYear
let selectedMonth = currentMonth
let selectedDay = currentDay

Component({
  ready() {

    let timeArr = this.data.defaultValue.split('-').map(i => Number(i))
    selectedYear = timeArr[0]
    selectedMonth = timeArr[1]
    selectedDay = timeArr[2]

    let months = []
    let days = []
    let monthStartFlag = 1
    let monthEndFlag = 12
    let dayStartFlag = 1
    let datEndFlag = getDayNum(timeArr[0],timeArr[1])

    if (timeArr[0] == currentYear) {
      monthStartFlag = currentMonth
    }
    if (timeArr[0] == currentYear && timeArr[1] == currentMonth){
      dayStartFlag = currentDay
    }

    for (let i = monthStartFlag; i <= monthEndFlag; i++) {
      months.push(i)
    }
    for (let i = dayStartFlag; i <= datEndFlag; i++) {
      days.push(i)
    }

    this.setData({
      months,
      days
    })

    let yearIndex = this.data.years.indexOf(timeArr[0])
    let monthIndex = this.data.months.indexOf(timeArr[1])
    let dayIndex = this.data.days.indexOf(timeArr[2])
    this.setData({
      yearDefaultIndex: yearIndex,
      monthDefaultIndex: monthIndex,
      dayDefaultIndex: dayIndex
    })
  },

  properties: {
    defaultValue: {
      type: String,
      value: `${currentYear}-${currentMonth}-${currentDay}`
    }
  },

  data: {
    years,
    months,
    days,
    yearDefaultIndex: null,
    monthDefaultIndex: null,
    dayDefaultIndex: null
  },

  methods: {
    pickerChange: function (ev) {
      let _this = this
      let index = ev.detail.value[0]
      let type = ev.target.dataset.type
      let typeMap = {
        year: function (index) {
          let year = _this.data.years[index]
          console.log(year,'年')
          selectedYear = year

          // 设置月
          let monthStartFlag = 1
          let months = []
          if (year == currentYear) {
            monthStartFlag = currentMonth

            let monthIndex = null
            let dayIndex = null

            if(selectedMonth <= currentMonth){
              selectedMonth = currentMonth
              monthIndex = 0
              if(selectedDay < currentDay){
                selectedDay = currentDay
                dayIndex = 0
              }else{
                dayIndex = selectedDay - currentDay
              }
            }else{
              monthIndex = selectedMonth - currentMonth
              dayIndex = selectedDay - 1
            }

            _this.setData({
              monthDefaultIndex: monthIndex,
              dayDefaultIndex: dayIndex
            })

          } else {
            setTimeout(() => {
              _this.setData({
                monthDefaultIndex: selectedMonth - 1,
                dayDefaultIndex: selectedDay - 1
              })
            }, 0)
          }
          for (let i = monthStartFlag; i <= 12; i++) {
            months.push(i)
          }
          _this.setData({
            months
          })

          // 设置日
          let dayStartFlag = 1
          let days = []
          let dayEndFlag = getDayNum(selectedYear, selectedMonth)
          if (selectedYear == currentYear && selectedMonth == currentMonth) {
            dayStartFlag = currentDay
          }
          for (let i = dayStartFlag; i <= dayEndFlag; i++) {
            days.push(i)
          }
          _this.setData({
            days
          })
        },
        month: function (index) {
          let month = _this.data.months[index]
          console.log(month,'月')
          selectedMonth = month
          let dayStartFlag = 1
          let days = []
          let dayEndFlag = getDayNum(selectedYear, selectedMonth)
          if (selectedYear == currentYear && selectedMonth == currentMonth) {
            dayStartFlag = currentDay

            selectedMonth = currentMonth
            selectedDay = currentDay

            _this.setData({
              monthDefaultIndex: 0,
              dayDefaultIndex: 0
            })
          } else {
            let selectedDayIndex = selectedDay - 1
            setTimeout(() => {
              if (selectedDayIndex >= _this.data.days.length) { // 大月最后一天会大于小月 
                selectedDayIndex = _this.data.days.length - 1
              }
              _this.setData({
                dayDefaultIndex: selectedDayIndex
              })
            }, 0)
          }
          for (let i = dayStartFlag; i <= dayEndFlag; i++) {
            days.push(i)
          }
          _this.setData({
            days
          })
        },
        day: function (index) {
          let day = _this.data.days[index]
          console.log(day,'日')
          selectedDay = day
        }
      }
      typeMap[type](index)
    },
    cancelAction: function () {
      this.triggerEvent('cancel')
    },
    confirmAction: function () {
      let year = selectedYear
      let month = selectedMonth
      let day = selectedDay
      if (month < 10) {
        month = '0' + month
      }
      if (day < 10) {
        day = '0' + day
      }
      this.triggerEvent('confirm', `${year}-${month}-${day}`)
    }
  }
})

wxml

<!--components/date_time_picker/index.wxml-->
<view class="picker-wrapper">

<view class="picker-toolbar">
      <text class="cancel" catch:tap="cancelAction">取消</text>
      <text class="confirm" catch:tap="confirmAction">确定</text>
</view>

<view class="picker-item-wrapper">

 <picker-view value="{{[yearDefaultIndex]}}" class="picker-item-year" indicator-style="height: 40px;" bindchange="pickerChange" data-type="year">
      <picker-view-column>
        <view wx:for="{{years}}" wx:key="{{index}}" class="picker-item-value">{{item}}年</view>
      </picker-view-column>
</picker-view>

 <picker-view value="{{[monthDefaultIndex]}}" class="picker-item-month" indicator-style="height: 40px;" bindchange="pickerChange" data-type="month">
      <picker-view-column>
        <view wx:for="{{months}}" wx:key="{{index}}" class="picker-item-value">{{item}}月</view>
      </picker-view-column>
</picker-view>

 <picker-view value="{{[dayDefaultIndex]}}" class="picker-item-day" indicator-style="height: 40px;" bindchange="pickerChange" data-type="day">
      <picker-view-column>
        <view wx:for="{{days}}" wx:key="{{index}}" class="picker-item-value">{{item}}日</view>
      </picker-view-column>
</picker-view>

</view>

</view>

/* components/date_time_picker/index.wxss */
@keyframes popupTitle {
  from {
    bottom: 0;
  }

  to {
    bottom: 40%;
  }
}

@keyframes popup {
  from {
    bottom: -40%;
  }

  to {
    bottom: 0rpx;
  }
}

.picker-wrapper {
  z-index: 999;
  position: fixed;
  top: 0;
  right: 0;
  left: 0;
  bottom: 0;
  background-color: rgba(0, 0, 0, 0.7);
}

.picker-wrapper .picker-toolbar {
  background-color: white;
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 48px;
  display: flex;
  align-items: center;
  font-size: 32rpx;
  justify-content: space-between;
  padding: 0 32rpx;
  animation: popupTitle 0.4s normal forwards;
}

.picker-wrapper .picker-toolbar .confirm {
  color: #006EFF;
}

.picker-wrapper .picker-item-wrapper {
  display: flex;
  background-color: white;
  position: absolute;
  right: 0;
  bottom: -40%;
  left: 0;
  height: 40%;
  animation: popup 0.4s normal forwards;
}

.picker-wrapper .picker-item-year,
.picker-item-month,
.picker-item-day {
  flex: 1;
}

.picker-wrapper .picker-item-year,
.picker-item-month,
.picker-item-day .picker-item-value {
  text-align: center;
  line-height: 40px;
}