小程序自定义日期组件,不显示今日之后的日期

官方picker可以设置有效时间,有效时间外的禁止选择,但是无法隐藏,于是决定通过picker-viewpicker-view-column来手写一个,效果如图:
在这里插入图片描述
需要注意的一些地方:

  1. 2月份,需要判断是平/闰年;
  2. 大小月,30或31天;
  3. 还有就是选择本年,控制显示月份,选择本月控制显示日。

组件 wxml

<slot bindtap="handlePicker"></slot>
  
<view hidden="{{!visible}}" class="date-picker-cover" bindtap="tapCancel"></view>
<view class="date-picker" animation="{{animationData}}">
    <view class="btn-area">
      <view class="btn-cancel" bindtap="tapCancel">取消</view>
      <view class="btn-confirm" bindtap="tapConfirm">确定</view>
    </view>
    <picker-view class="picker-view" value="{{value}}" bindchange="changeDate">
      <picker-view-column>
          <view wx:for="{{years}}" wx:key="index" class="picker-view-column">{{item}}年</view>
        </picker-view-column>
      <picker-view-column>
          <view wx:for="{{showDate.months}}" wx:key="index" class="picker-view-column">{{item > 9 ? item : '0' + item}}月</view>
        </picker-view-column>
      <picker-view-column>
          <view wx:for="{{showDate.days}}" wx:key="index" class="picker-view-column">{{item > 9 ? item : '0' + item}}日</view>
        </picker-view-column>
    </picker-view>
  </view>

组件 js

Component({
  /**
   * 组件的属性列表
   */
  properties: {
    // 日期 格式 yyyy-MM-DD
    dateValue: {
      type: String,
      observer: function (val) {
        if (val) {
          this.initDate(val)
        }
      }
    }
  },

  /**
   * 组件的初始数据
   */
  data: {
    visible: false,
    years: [],
    curDate: {
      year: null,
      month: null,
      day: null
    },
    // 全部月、日
    fullDate: {
      months: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
      days: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]
    },
    // 显示月、日
    showDate: {
      months: [],
      days: []
    },
    value: null,
    dateArr: null,
    formatDate: '',
    animate: null,
    animationData: null
  },
  pageLifetimes: {
    show() {
      let animate = wx.createAnimation({
        duration: 400,
        timingFunction: 'ease',
      })
      this.setData({
        animate
      })
    }
  },
  /**
   * 组件的方法列表
   */
  methods: {
    // 选择日期
    handlePicker() {
      const slideUp = this.data.animate.bottom(0).step()
      this.setData({
        animationData: slideUp.export(),
        // 弹出日期时,显示确定的时间
        value: this.data.value,
        visible: true
      })
    },
    // 初始化日期
    initDate(val) {
      const date = new Date()
      const curDate = {
        year: date.getFullYear(),
        month: date.getMonth() + 1,
        day: date.getDate()
      }
      
      let years = []
      for (let i = 1; i <= curDate.year; i++) {
        years.push(i)
      }
      const value = val.split('-')
      this.setData({
        years,
        curDate,
        value: value.map(item => Number(item) - 1)
      })
      this.computedDate(value)
    },
    // 选择日期
    changeDate(val) {
      let value = val.detail.value.map(item => item + 1)
      this.computedDate(value)
      const month = value[1] > 9 ? value[1] : '0' + value[1]
      const day = value[2] > 9 ? value[2] : '0' + value[2]
      this.setData({
        dateArr: val.detail.value,
        formatDate: `${value[0]}-${month}-${day}`,
      })
    },
    // 计算月、日
    computedDate (val) {
      const { months: fullMonths, days: fullDays } = this.data.fullDate
      const year = Number(val[0])
      const month = Number(val[1])
      // 闰年:能被 4 整除并且不能被 100 整除,或者被 400 整除
      const leapYear = !(year % 4) && (year % 100) || !(year % 400) ? true : false
      // 默认大月 0:2月 1:小月
      let monthType = null
      if (month === 2) {
        monthType = 0
      } else if ([4, 6, 9, 11].includes(month)) {
        monthType = 1
      }

      // 本年显示 ≤ 本月
      let months = year === this.data.curDate.year ? fullMonths.slice(0, this.data.curDate.month) : fullMonths

      let days = fullDays
      if (year === this.data.curDate.year && month === this.data.curDate.month) {
        // 本年且本月,显示 ≤ 本日
        days = fullDays.slice(0, this.data.curDate.day)
      } else {
        if (monthType === 0) {
          // 2月
          days = leapYear ? fullDays.slice(0, 29) : fullDays.slice(0, 28)
        } else if (monthType === 1) {
          // 小月
          days = fullDays.slice(0, 30)
        }
      }
      this.setData({
        ['showDate.months']: months,
        ['showDate.days']: days
      })
    },
    // 确定
    tapConfirm() {
      const slideDown = this.data.animate.bottom('-560rpx').step()
      this.triggerEvent('change', this.data.formatDate)
      this.setData({
        value: this.data.dateArr,
        animationData: slideDown.export(),
        visible: false
      })
    },
    // 取消
    tapCancel() {
      const slideDown = this.data.animate.bottom('-560rpx').step()
      this.setData({
        animationData: slideDown.export(),
        visible: false
      })
    }
  }
})

组件 wxss

.date-picker-cover {
  width: 100vw;
  height: 100vh;
  background-color: rgba(0, 0, 0, .5);
  position: fixed;
  top: 0;
  left: 0;
  z-index: 99;
}
.date-picker {
  width: 100%;
  position: absolute;
  left: 0;
  bottom: 0;
  background-color: #fff;
  position: fixed;
  bottom: -560rpx;
  left: 0;
  z-index: 100;
}
.date-picker .btn-area {
  box-sizing: border-box;
  width: 100%;
  display: flex;
  justify-content: space-between;
  padding: 18rpx 30rpx;
  border-bottom: 2rpx solid #f6f6f6;
  font-size: 32rpx;
}
.date-picker .btn-area .btn-cancel {
  color: #7f7f7f;
}
.date-picker .btn-area .btn-confirm {
  color: #07c160;
}
.date-picker .picker-view {
  width: 100%;
  height: 480rpx;
}
.date-picker .picker-view .picker-view-column {
  line-height: 34px;
  text-align: center;
  font-size: 32rpx;
}

调用组件

<!-- wxml -->
<view>
  <date-picker dateValue="{{date}}" bindchange="changeDate">
    <view class="date-content">选择日期:{{date}}</view>
  </date-picker>
</view>
// js
Page({
  data: {
    date: '2021-12-02'
  },
  onLoad() {
  },
  changeDate(val) {
    this.setData({
      date: val.detail
    })
  }
})
// json
{
  "usingComponents": {
    "date-picker": "/components/date-picker/date-picker"
  }
}
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
微信小程序提供了日期时间选择器组件`picker`和日历组件`calendar`,但如果需要自定义样式或者功能,可以考虑封装一个日期时间组件。 以下是一个简单的日期时间组件的封装示例: 1. 在`/components`目录下创建一个`datetime-picker`文件夹,创建`datetime-picker.wxml`、`datetime-picker.wxss`、`datetime-picker.js`和`datetime-picker.json`四个文件。 2. 在`datetime-picker.json`中定义组件的属性: ```json { "component": true, "usingComponents": {}, "properties": { "startDate": { "type": String, "value": "2023-02-15", }, "endDate": { "type": String, "value": "2023-02-20", }, "startTime": { "type": String, "value": "00:00", }, "endTime": { "type": String, "value": "23:59", }, "defaultDate": { "type": String, "value": "", }, "defaultTime": { "type": String, "value": "", }, "format": { "type": String, "value": "datetime", }, "showTime": { "type": Boolean, "value": true, }, "showDate": { "type": Boolean, "value": true, }, "startPlaceholder": { "type": String, "value": "开始时间", }, "endPlaceholder": { "type": String, "value": "结束时间", }, "bind:change": { "type": Function, "value": "", } }, "options": { "styleIsolation": "apply-shared" } } ``` 上述属性中: - `startDate`和`endDate`为日期范围,用于限制可选日期的范围; - `startTime`和`endTime`为时间范围,用于限制可选时间的范围; - `defaultDate`和`defaultTime`为默认值; - `format`为显示格式,支持`datetime`、`date`和`time`三种格式; - `showTime`和`showDate`分别控制是否显示时间和日期选择器; - `startPlaceholder`和`endPlaceholder`为开始时间和结束时间的占位符; - `bind:change`为选择器值变化时的回调函数。 3. 在`datetime-picker.wxml`中定义选择器组件: ```html <view class="datetime-picker"> <view wx:if="{{showDate}}" class="datetime-picker-item"> <picker mode="date" start="{{startDate}}" end="{{endDate}}" value="{{selectedDate}}" bindchange="onDateChange"> <view class="datetime-picker-value"> <text wx:if="{{selectedDate}}">{{selectedDate}}</text> <text wx:else>{{startPlaceholder}}</text> </view> </picker> </view> <view wx:if="{{showTime}}" class="datetime-picker-item"> <picker mode="time" start="{{startTime}}" end="{{endTime}}" value="{{selectedTime}}" bindchange="onTimeChange"> <view class="datetime-picker-value"> <text wx

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ZionHH

落魄前端,在线炒粉

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值