微信小程序(自定义calendar组件)时间选择组件(单选和多选)

该代码实现了一个用于选择日期范围的JavaScript组件,包括单选日期和选择日期区间功能。组件初始化时会根据给定的起止时间戳设置当前显示的年月日,并提供获取当前日期、切换上下月份以及选择日期的方法。同时,它还处理了日期选择的逻辑,确保选择的日期在有效范围内。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在这里插入图片描述
js

// components/shopLists/index.js
const app = getApp()
Component({
  externalClasses: ['custom-class'],
  properties: {
    type: {
      type: String,
      value: 'range', //single表示单选,range表示选择日期区间
    },
    startTimestamp: { // 选择开始时间
      type: String,
      value: ''
    },
    endTimestamp: { // 选择结束时间
      type: String,
      value: ''
    }
  },
  data: {
    week: ['一', '二', '三', '四', '五', '六', '日'],
    dateList: [],
    showYear: '', //页面上展示的年
    showMonth: '', //页面上展示的月
    showDay: '', //页面上展示的日
    startSelectYear: '', //开始选中的年
    startSelectMonth: '', //开始选中的月
    startSelectDay: 0, //开始选中的日
    currentYear: '', //当前年
    currentMonth: '', //当前月
    currentTime: '2021-01', //当前年月日
    // startTimestamp: '', //开始的时间戳
    // endTimestamp: '', //结束的时间戳
    host: app.globalData.hostImage,
  },
  lifetimes: {
    ready() {
      const {
        startTimestamp,
        endTimestamp
      } = this.data
      const now = new Date();
      console.log('startTimestamp', this.data.startTimestamp, this.data.endTimestamp, this.timestamp(this.data.startTimestamp), this.timestamp(this.data.endTimestamp))
      const newTime = Date.parse(new Date(now.getFullYear(), now.getMonth(), now.getDate()));
      this.setData({
        currentYear: now.getFullYear(),
        currentMonth: now.getMonth() + 1,
        showMonth:3,
        startTimestamp: startTimestamp ? this.timestamp(startTimestamp) : newTime,
        endTimestamp: this.timestamp(endTimestamp)
      })
      this.getCurrentData();
      this.getDay()
    }
  },
  observers: {
    monthTranslate() {
      this.data.dateList.some(val => {
        Object.keys(this.data.monthTranslate).some(item => {
          if (val.label * 1 == item) {
            val.status = this.data.monthTranslate[item].toString()
            delete this.data.monthTranslate[item];
            return
          }
        })
        if (Object.keys(this.data.monthTranslate).length === 0) {
          return
        }
      })
      this.setData({
        dateList: this.data.dateList
      })
    }
  },
  methods: {
    timestamp(e) {
      let time = new Date(e)
      // console.log('0000000000000', time)
      const yy = time.getFullYear()
      const mm = time.getMonth() + 1
      const dd = new Date(time).getDate()
      time = yy + '/' + mm + '/' + dd
      console.log(e, yy, mm, dd)
      return Date.parse(time)
    },
    getDay() {
      const {
        showYear,
        showMonth,
        showDay
      } = this.data;
      // var firstDay = new Date(`${showYear}, ${showMonth}, 1`).getDay(); //获得每月1号是星期几
      var firstDay = new Date(showYear,showMonth-1,1).getDay(); //获得每月1号是星期几
      let days = new Date(showYear, showMonth, 0).getDate(); //获取当月多少天
      this.data.dateList = [];
      console.log('firstDay',firstDay)
      for (let s = 1; s <= firstDay - 1; s++) {
        this.data.dateList.push({
          label: '',
          timestamp: 0
        })
      }
      for (let i = 1; i <= days; i++) {
        const time = showYear + '/' + showMonth + '/' + i
        this.data.dateList.push({
          label: i < 10 ? '0' + i : i,
          timestamp: Date.parse(time)
        })
      }
      this.setData({
        dateList: this.data.dateList,
        showYear,
        showMonth
      })
      console.log('asdjasd', this.data.dateList)
      if (this.data.startSelectYear === '') {
        this.data.startSelectYear = showYear
        this.data.startSelectMonth = showMonth
        this.data.startSelectDay = showDay
      }
      this.triggerEvent("changTime", {
        showYear,
        showMonth
      })
    },
    getCurrentData() { //获取当前日期,初始化使用
      const date = new Date(this.uDateFormat(this.data.startTimestamp));
      this.data.showYear = date.getFullYear();
      this.data.showMonth = date.getMonth() + 1;
      this.data.showDay = date.getDate();
    },
    getNextMonth() { //获取下个月
      if (this.data.showMonth < 12) {
        this.data.showMonth += 1;
      } else {
        this.data.showMonth = 1;
        this.data.showYear += 1;
      }
      this.getDay();
    },
    bindPickerChange(e) { //下拉选择年月
      const {
        value
      } = e.detail;
      this.data.showYear = value.split('-')[0] * 1;
      this.data.showMonth = value.split('-')[1] * 1;
      this.getDay();
    },
    getLastMonth() { //获取上个月
      if (this.data.showMonth !== 1) {
        this.data.showMonth -= 1;
      } else {
        this.data.showMonth = 12;
        this.data.showYear -= 1;
      }
      this.getDay();
    },
    selectDate(e) {
      const {
        date
      } = e.currentTarget.dataset;
      if (!date) {
        return;
      }
      const {
        showYear,
        showMonth,
        startSelectYear,
        startSelectMonth,
        startSelectDay,
        endTimestamp
      } = this.data;
      const currentTimestamp = Date.parse(new Date(showYear, showMonth - 1, date * 1)); //当前选中的时间戳
      if (this.data.type === 'single') { //单选日期
        this.setData({
          startTimestamp: currentTimestamp,
          endTimestamp: currentTimestamp
        })
        this.triggerEvent('getCalendarTime', {
          startTime: this.uDateFormat(this.data.startTimestamp),
          endTime: this.uDateFormat(this.data.endTimestamp)
        })
        return
      }
      const startTimestamp = Date.parse(new Date(startSelectYear, startSelectMonth - 1, startSelectDay * 1)); //已经选择的开始时间的时间戳
      if (this.data.startSelectYear === '' || currentTimestamp < startTimestamp || (currentTimestamp > startTimestamp && currentTimestamp <= endTimestamp)) {
        this.setData({
          startTimestamp: currentTimestamp,
          endTimestamp: this.data.endTimestamp >= currentTimestamp ? this.data.endTimestamp : currentTimestamp
        })
        console.log('startTimestamp', this.data.startTimestamp, 'endTimestamp', this.data.endTimestamp)
        this.data.startSelectYear = showYear;
        this.data.startSelectMonth = showMonth;
        this.data.startSelectDay = date;
        //如果选择了开始和结束日期中间的日期,则初始化日期
        if (currentTimestamp > startTimestamp && currentTimestamp < endTimestamp) {
          this.setData({
            endTimestamp: currentTimestamp
          })
        }
        this.triggerEvent('getCalendarTime', {
          startTime: this.uDateFormat(this.data.startTimestamp),
          endTime: this.uDateFormat(this.data.endTimestamp)
        })
        return;
      }
      this.setData({
        endTimestamp: currentTimestamp //结束的时间戳
      })
      this.triggerEvent('getCalendarTime', {
        startTime: this.uDateFormat(this.data.startTimestamp),
        endTime: this.uDateFormat(this.data.endTimestamp)
      })
    },
    // 时间戳转日期时间格式: yyyy-MM-dd
    uDateFormat(timestamp) {
      return this.uMoment(Number(timestamp)).format('yyyy-MM-dd')
    },
    uMoment(timestamp) {
      const leftPad = (num) => {
        if (num < 10) {
          return `0${num}`
        }
        return `${num}`
      }
      const date = new Date(timestamp)

      return {
        format(pattern) {
          const str = typeof pattern === 'string' ? pattern : 'yyyy-MM-dd'
          if (!Number.isNaN(date.getTime())) {
            return str
              .replace(/yyyy/i, leftPad(date.getFullYear()))
              .replace(/MM/, leftPad(date.getMonth() + 1))
              .replace(/dd/i, leftPad(date.getDate()))
              .replace(/hh/i, leftPad(date.getHours()))
              .replace('mm', leftPad(date.getMinutes()))
              .replace(/ss/i, leftPad(date.getSeconds()))
          }
          return ''
        }
      }
    },
    resetTime(e) {
      if (e == 'noNUll') {
        this.setData({
          startTimestamp: this.timestamp(this.data.startTimestamp),
          endTimestamp: this.timestamp(this.data.endTimestamp),
        })
      } else {
        this.setData({
          startTimestamp: '',
          endTimestamp: '',
          startSelectYear: '', //开始选中的年
          startSelectMonth: '', //开始选中的月
          startSelectDay: 0, //开始选中的日
        })
      }
      console.log('dateList',this.data)
    }
  }
})

wxml

<view class="calendar custom-class">
  <view class="flex spaceBetween align-center" style="color:#18284E;">
    <view>选择时间范围</view>
    <view class="flex align-center">
      <image src="{{host}}timeRightIcon.png" bindtap="getLastMonth" class="icon_arrows_left icon_arrows_tip">
      </image>
      <text class="title">{{showYear}}{{showMonth}}</text>
      <image src="{{host}}timeRightIcon.png" class="icon_arrows_right icon_arrows_tip" bindtap="getNextMonth"
        wx:if='{{currentYear > showYear || (currentYear === showYear && currentMonth > showMonth)}}'></image>
      <!-- <image src="../../image/timeRightIcon.png" class="icon_arrows_tip" wx:else></image> -->
    </view>
  </view>
  <view class="week_list sizeTwentyTwo">
    <text wx:for="{{week}}" wx:key="index" class="sizeColorMianThree">{{item}}</text>
  </view>
  <view class="day_list flex sizeTwentyTwo">
    <view wx:for="{{dateList}}" class="daybox" bindtap="selectDate" data-date="{{item.label}}">
      <span
        class="date_item {{(item.timestamp == endTimestamp || item.timestamp == startTimestamp)?'selectDate_item':''}}"
        wx:if="{{(item.timestamp == endTimestamp && endTimestamp!=='') || (item.timestamp == startTimestamp&&startTimestamp!=='')}}">{{item.label}}</span>
      <view
        class="day {{item.timestamp<=endTimestamp&&item.timestamp>=startTimestamp&&endTimestamp!=startTimestamp?'selectDateBg':''}} {{((item.timestamp == endTimestamp)&&(endTimestamp!=startTimestamp))?'borderRadiusRigth':''}} {{item.timestamp == startTimestamp&&(endTimestamp!=startTimestamp)?'borderRadiusLeft':''}}">
        {{item.label}}</view>
      <view wx:if="{{(index+1)%7!==0}}"
        class="leftBox {{item.timestamp<endTimestamp&&item.timestamp>=startTimestamp?'selectDateBg':''}}"></view>
    </view>
  </view>
</view>

wxss

.flex {
  display: flex;
}
/* 两端对其 */
.spaceBetween {
  justify-content: space-between;
}
/* 垂直居中 */
.align-center {
  align-items: center;
}
/* 字体22rpx */
.sizeTwentyTwo {
  font-size: 22rpx;
}

page {
  background: #f6f6f6;
}

.calendar {
  padding: 10rpx 0rpx;
  box-sizing: border-box;
}

.title {
  font-size: 26rpx;
  font-weight: 500;
  line-height: 48rpx;
  margin-right: 64rpx;
  margin-left: 64rpx;
}

.icon_arrows_left {
  transform: rotate(180deg);
}

.calendar .week_list {
  display: flex;
  padding-top: 35rpx;
}

.calendar .week_list text {
  height: 64rpx;
  width: 64rpx;
  line-height: 64rpx;
  box-sizing: border-box;
  margin-left: 40rpx;
  text-align: center;
}

.calendar .week_list text:first-child {
  margin-left: 0rpx;
}

.calendar .day_list {
  flex-wrap: wrap;
  display: flex;
}

.calendar .day_list .daybox {
  color: rgba(24, 40, 78, 0.85);
  height: 64rpx;
  line-height: 64rpx;
  margin-top: 20rpx;
  box-sizing: border-box;
  text-align: center;
  position: relative;
  display: flex;
  justify-content: center;
  align-items: center;
}


.calendar .day_list .daybox:nth-child(7n+1) .day {
  border-radius: 30rpx 0rpx 0rpx 30rpx;
}


.calendar .day_list .daybox:nth-child(7n) .day {
  border-radius: 0rpx 30rpx 30rpx 0rpx;
}

.borderRadiusLeft {
  border-radius: 30rpx 0rpx 0rpx 30rpx !important;
}

.borderRadius {
  border-radius: 30rpx;
}

.borderRadiusRigth {
  border-radius: 0rpx 30rpx 30rpx 0rpx !important;
}

.day {
  width: 64rpx;
  height: 64rpx;
}

.leftBox {
  width: 40rpx;
  height: 64rpx;
}

.calendar .day_list .daybox:nth-child(7n) {
  border-radius: 0rpx 30rpx 30rpx 0rpx;
}

.calendar .day_list .date_item {
  position: relative;
}


.calendar .day_list .selectDate_item {
  z-index: 2;
  color: #fff !important;
}

.calendar .day_list .selectDate_item {
  width: 64rpx;
  height: 64rpx;
  background: #2F54EB;
  position: absolute;
  border-radius: 100%;
  z-index: 1;
  left: 0rpx;
}

.calendar .day_list .selectDateBg {
  background: rgba(47, 84, 235, 0.06);
}

.icon_arrows_tip {
  width: 32rpx;
  height: 32rpx;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值