背景

在业务中有时需要以周为单位选择日期,将某个周的开始和结束日期回显在界面上。这种需求在pc端上有现成的组件可以使用,比如elementUI的el-date-picker组件即可实现。但是在原生小程序中并没有现成可用的组件实现这种需求,那么只能自定义一个这样的周组件或者基于第三方日历组件二次封装实现一个周组件。

二次封装周组件

准备工作

  • 熟悉第三方日历组件
    这里采用的是小历同学开发的开源日历组件进行二次封装,使用说明文档可点击第三方日历组件
  • 需要熟悉的方法和属性
    日历组件中的禁用日期属性disableMode、每周第一天是周日还是周一属性firstDayOfWeek、默认选中的日期属性defaultDay、是否开启日期范围选择模式属性chooseAreaMode、取消所有选中日期的方法cancelSelectedDates、选中指定日期范围的方法chooseDateArea、还有日期选择后的事件afterTapDay。
  • 获取周时间范围的算法
            let year=e.detail.year
            let month=e.detail.month
            month=month<10?'0'+month:month
            let day=e.detail.day
            day=day<10?'0'+day:day
            let date=year+'-'+month+'-'+day
        let weekOfday = moment(date, "YYYY-MM-DD").format("E"); //计算今天是这周第几天
        let startTime = moment(date)
          .subtract(weekOfday - 1, "days")
          .format("YYYY-MM-DD"); //周一日期
        let endTime = moment(date).weekday(7).format("YYYY-MM-DD"); //周日日期
        if(moment(date).day()==0){
          endTime=date
        }

实现

  • 思路
    (1)当组件第一次加载进来后,根据当前时间算出本周的开始和结束时间范围,然后调用组件的chooseDateArea方法实现周日期的默认选中。

(2)当点击改变日历组件上的日期后,调用afterTapDay事件的回调函数afterTapDay:计算出所选日期所在周的日期范围,然后调用chooseDateArea方法将指定范围的日期选中。
注意
这里要在执行回调函数afterTapDay开始要调用日历组件的cancelSelectedDates方法取消所有已选择的日期,否则会导致周日期选择错乱。
(3)在回调函数最后将计算出的周范围的日期放入变量中,当点击确定选择日期后回显到页面并把筛选日期范围传递给调用者(父组件)

  • 实现代码
    html代码
<view class="select-period" hidden="{{!selectDateShow}}"  catchtouchmove="return">
    <view class="select_top">
  <view class="t_singer t2{{!selectDateShow?'t_active':''}}"></view>
</view>
<view class="sg"></view>
<view>
    <view style="background: #f5f5f5;padding-top: 15rpx;" wx:if="{{selectPeriod=='week'}}">
  <view class="date">
    <calendar style="height: 100%;" preYear="true" nextYear="true"  bind:afterTapDay="afterTapDay" id="mycalendar" 
    calendarConfig="{{calendarConfig}}"   bind:whenChangeMonth="whenChangeMonth"
    ></calendar>
    <slot>
    </slot>
  </view>
    <view class="btns" style="margin-top: 29rpx;">
      <view class="cancel" bindtap="cancel">取消</view>
      <view class="ok" bindtap="setlect_date">确定</view>
</view>
</view>
<view class="monthly" style="height: {{selectPeriod=='month'?'757rpx':'360rpx'}};" hidden="{{selectPeriod=='week'}}">
<view class="m_year">
<view class="m_title">选择年份</view>
<view class="select_year">
    <image src="../../../image/y_right.png" bindtap="reduce" class="m_img" style="transform: rotate(180deg);"></image>
  <view class="year">{{yearRes}}年</view>
  <image src="../../../image/y_right.png" bindtap="add" class="m_img"></image>
</view>
</view>
<view class="date-box">
<view class="m_month" hidden="{{selectPeriod!='month'}}">
<view class="m_title">选择月份</view>
<view class="month_list">
<view  wx:for="{{monthList}}" bindtap="selectMonth" data-value="{{item.value}}" data-canSel="{{item.avaliable}}" wx:key="index" class="m_singer {{monthRes==item.value?'m_singer_active':''}}" style="color: {{item.avaliable?'rgba(0,0,0,0.8)':'#c7c7c7'}};">{{item.name}}</view>
</view>
</view>
<!-- <view class="week-box" wx:if="{{selectPeriod=='week'}}">
    <view class="m_month" hidden="{{selectPeriod!='week'}}">
<view class="m_title">选择周</view>
<view class="week_list">
<view  wx:for="{{weekData}}" bindtap="selectMonth" data-value="{{item.value}}" wx:key="index" class="week-item {{weekRes==item.value?'m_singer_active':''}}"
 data-endTime="{{item.endTime}}"
>
<view>{{item.name}}</view>
<view class="date-range">{{item.dates}}</view>
</view>
</view>
</view>
</view> -->
<view class="btns" style="margin-top: 29rpx;">
      <view class="cancel" bindtap="cancel">取消</view>
      <view class="ok" bindtap="setlect_month_two">确定</view>
</view>
</view>
</view>
</view>
</view>

css代码

/* pages/common/select-period/select-period.wxss */
.select-period{
    position: fixed;
    left: 0;
    top: 200rpx;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.6);
    z-index: 999999999999;
}
.period-content{
    width: 100%;
    height: 413rpx;
    background: #F5F5F5;
}
.lable{
    display: block;
    width: 300rpx;
    height: 90rpx;
    display: flex;
    margin: 30rpx 0 0 30rpx;
}
.radioGroup{
    font-size: 28rpx;
    color: rgba(1, 1, 1, 0.8);
    font-weight: 400;
    width: 690rpx;
    height: 258rpx;
    margin: 0 auto;
    display: flex;
    justify-content: space-between;
    flex-wrap: wrap;
    background: #fff;
}
.btns{
    width: 750rpx;
    height: 120rpx;
    background-color: #fff;
    display: flex;
    padding: 0 31rpx;
    box-sizing: border-box;
    justify-content: space-between;
    align-items: center;
    position: relative;
    z-index: 9999;
}
.cancel{
    width: 320rpx;
    height: 80rpx;
    background: #FFFFFF;
    border: 1px solid rgba(0, 0, 0, 0.3);
    border-radius: 40rpx;
    font-size: 32rpx;
    font-family: Source Han Sans SC;
    font-weight: 400;
    color: #646464;
    text-align: center;
    line-height: 80rpx;
    position: relative;
    z-index: 999999999;
}
.ok{
    width: 320rpx;
    height: 80rpx;
    background: #505BD2;
    border-radius: 40rpx;
    font-size: 32rpx;
    font-family: Source Han Sans SC;
    font-weight: 400;
    color: #fff;
    text-align: center;
    line-height: 80rpx;
    position: relative;
    z-index: 999999999;
}
.monthly{
    width: 100%;
    height: 757rpx;
    background: #F5F5F5;
    padding-top: 15rpx;
    box-sizing: border-box;
}
.m_year{
    width: 690rpx;
    height: 210rpx;
    background: #FFFFFF;
    border-radius: 6px;
    margin: 0 auto;
}
.m_title{
    display: block;
    font-family: Source Han Sans SC;
    font-weight: 400;
    color: rgba(1, 1, 1, 0.8);
    line-height: 68rpx;
    font-size: 28rpx;
    padding-left: 31rpx;
    border-bottom: 1rpx solid rgba(0, 0, 0, 0.1);
}
.year{
    width: 268rpx;
    height: 60rpx;
    background: #FFFFFF;
    /* border: 1px solid rgba(0, 0, 0, 0.15); */
    border-radius: 4rpx;
    text-align: center;
    line-height: 60rpx;
    font-size: 28rpx;
    font-family: Source Han Sans SC;
    font-weight: 400;
    color: rgba(0, 0, 0, 0.8);
}
.select_year{
    display: flex;
    height: 142rpx;
    align-items: center;
    padding: 0 173rpx;
    box-sizing: border-box;
}
.reduce{
    width: 0;
    height: 0;
    border-left: 10rpx solid transparent;
    border-top: 10rpx solid transparent;
    border-right: 10rpx solid #000;
    border-bottom: 10rpx solid transparent;
    margin-right: 25rpx;
}
.reduce_dis{
    border-right: 10rpx solid #c8c8c8;
}
.add{
    border-left: 10rpx solid #000;
    border-right: 10rpx solid transparent;
    margin-left: 25rpx;
}
.add_dis{
    border-left: 10rpx solid #c8c8c8; 
}
.m_month{
    width: 690rpx;
    height: 360rpx;
    background: #FFFFFF;
    border-radius: 6px;
    margin: 0 auto;
    margin-top: 20rpx;
}
.month_list{
    display: flex;
    justify-content: space-between;
    flex-wrap: wrap;
}
.m_singer{
    width: 68rpx;
    height: 68rpx;
    background: #fff;
    border-radius: 50%;
    font-size: 26rpx;
    line-height: 68rpx;
    text-align: center;
    font-family: Source Han Sans SC;
    font-weight: 400;
    color: rgba(0,0,0, 0.8);
    margin: 16rpx 40rpx;
}
.m_singer_active{
    color: rgba(255,255,255, 0.8);
    background: #505BD2;
}
.deviceType{
    width: 100%;
    background: #F5F5F5;
    height: 685rpx;
    padding-top: 15rpx;
    box-sizing: border-box;
}
.cont{
width: 690rpx;
height: 522rpx;
background: #FFFFFF;
border-radius: 6rpx;
margin: 0 auto;
padding: 30rpx 20rpx;
box-sizing: border-box;
}
.cont_t{
    display: flex;
    justify-content: space-between;
    flex-wrap: wrap;
}
.type_singer{
    width: 310rpx;
    height: 76rpx;
    background: #F5F5F5;
    border-radius: 38rpx;
    font-size: 26rpx;
    font-family: Source Han Sans SC;
    font-weight: 400;
    color: #000000;
    text-align: center;
    line-height: 76rpx;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    padding: 0 26rpx;
    box-sizing: border-box;
    margin-bottom: 20rpx;
}
.type_singer_active{
    background: #505BD2;
    color: #fff;
}
.date{
    background: #fff;
    width: 690rpx;
    /* height: 563rpx; */
    border-radius: 6rpx;
    margin: 0 auto;
}
.select_top{
    width:750rpx;
    height: 44rpx;
    padding: 0 31rpx;
    box-sizing: border-box;
    position: absolute;
    left: 0;
    top: -63rpx;
}
.select_toptwo{
    width:750rpx;
    height: 44rpx;
    padding: 0 31rpx;
    box-sizing: border-box;
    position: fixed;
    left: 0;
    top: 137rpx;
    z-index:9999999999;
}
.t_singer{
    width: 400rpx;
    height: 100%;
    background: #f5f5f5;
}
.t_active{
    display: none;
}
.t1{
    position: absolute;
    left: 30rpx;
    top: 0;
}
.t2{
    position: absolute;
    left: 320rpx;
    top: 0;
}
.t3{
    position: absolute;
    left: 512rpx;
    top: 0;
}
.sg{
    position: absolute;
    left: 0;
    top: -20rpx;
    width: 750rpx;
    height: 20rpx;
    background: #F5F5F5;
    border: none !important;
}
.check {
    width: 44rpx;
    height: 44rpx;
    background: #fff;
    display: flex;
    justify-content: center;
    align-items: center;
    border: 1px solid rgba(0, 0, 0, 0.15);
    border-radius: 50%;
    margin-right: 10rpx;
}
.checks{
    background: #505BD2 ;
}
.calendar {
    width: 100%;
    text-align: center;
    font-size: 30rpx;
    box-sizing: border-box;
}

.calendar_header {
    line-height: 70rpx;
    font-size: 30rpx;
    text-align: left;
    padding: 0 60rpx;
    box-sizing: border-box;
    background: #fff;
    height: 84rpx;
    border-bottom: 1rpx solid rgba(0, 0, 0, 0.1);
}

.header_left {
    flex: 1;
    /* display: inline-flex; */
    justify-content: space-between;
    height: 84rpx;
    align-items: center;
    font-size: 24rpx;
    font-family: Source Han Sans SC;
    font-weight: 400;
    color: rgba(0, 0, 0, 0.6);
    
}
.header_year{
    width: 158rpx;
    height: 44rpx;
    background: #FFFFFF;
    border: 1rpx solid rgba(0, 0, 0, 0.15);
    border-radius: 4rpx;
    line-height: 44rpx;
    margin-right: 20rpx;
    position: relative;
    padding-left: 22rpx;
    box-sizing: border-box;
}
.header_year::after{
    content: "";
    width: 10rpx;
    height: 10rpx;
    position: absolute;
    right: 15rpx;
    top:12rpx;
    border-right: 1rpx solid #B4B4B4;
    border-bottom: 1rpx solid #B4B4B4;
    transform: rotate(45deg);
    transition: all .2s ease;
}
.s_ay::after{
    content: "";
    width: 10rpx;
    height: 10rpx;
    position: absolute;
    right: 15rpx;
    top:18rpx;
    border-right: 1rpx solid #B4B4B4;
    border-bottom: 1rpx solid #B4B4B4;
    transform: rotate(225deg);
    transition: all .2s ease;
    transform: rotate(225deg);
}
.header_month{
    width: 128rpx;
    height: 44rpx;
    background: #FFFFFF;
    border: 1rpx solid rgba(0, 0, 0, 0.15);
    border-radius: 4rpx;
    line-height: 44rpx;
    position: relative;
    padding-left: 30rpx;
    box-sizing: border-box;
}
.header_month::after{
    content: "";
    width: 10rpx;
    height: 10rpx;
    position: absolute;
    right: 15rpx;
    top:12rpx;
    border-right: 1rpx solid #B4B4B4;
    border-bottom: 1rpx solid #B4B4B4;
    transform: rotate(45deg);
    transition: all .2s ease;
}

.header_left .header_preMonth,
.header_nextMonth {
    min-width: 50rpx;
    text-align: center;
}

.header_right {
    flex: 1;
    text-align: right;
    padding: 0 20px;
    display: inline-block;
    float: right;
}

.header_title {
    min-width: 300rpx;
    text-align: center;
    font-size: 28rpx;
    font-family: Arial;
    font-weight: 400;
    color: rgba(0, 0, 0, 0.8);
}

.calendar_weeks {
    display: flex;
    text-align: center;
    padding: 20rpx 10rpx;
    box-sizing: border-box;
    /* border-top: 1rpx solid #e0e0e0; */
    /* border-bottom: 1rpx solid #e0e0e0; */
    /* background: #f5f5f5; */
}

.weeks_item {
    flex: 1;
    font-size: 24rpx;
font-family: Source Han Sans SC;
font-weight: 400;
color: rgba(0, 0, 0, 0.5) !important;
}

.calendar_days {
    display: flex;
    flex-wrap: wrap;
    padding: 10rpx 10rpx 20rpx 10rpx;
    box-sizing: border-box;
}

.days_grid {
    display: inline-block;
    width: 14.28571428571429%;
    line-height: 70rpx;
    position: relative;
    z-index: 1;
}

.days_grid .pre,
.next {
    color: #ccc;
}

.thisDayIsSelect {
    background: rgb(49, 120, 228);
    border-radius: 50%;
    color: #fff;
    width: 70rpx;
    height: 70rpx;
    font-size: 28rpx;
    font-family: Arial;
    font-weight: 400;
    color: rgba(255, 255, 255, 0.8) !important;
}

.thisDayNoSelect {
    background: rgb(239, 241, 245);
    border-radius: 50%;
    width: 72%;
    margin: 0 auto;
}

.calendar_timer {
    border-top: 1rpx solid #e0e0e0;
    border-bottom: 1rpx solid #e0e0e0;
    display: flex;
    align-items: center;
}

.timer_picker {
    flex: 1
}

.timer_picker__view {
    display: flex;
    justify-content: flex-start;
    align-items: center;
    flex: 1;
}

.timer_picker__view text {
    padding: 10px;
    flex: 0.2;
}

.timer_picker__view input {
    padding: 10px;
    flex: 0.8;
    text-align: left;
}

.timer_now {
    padding: 10px;
    flex: 0.3;
}
.putThe{
    color: #989898 !important;
}

.noSelect{
    font-family: Source Han Sans SC;
    font-weight: 400;
    color: rgba(0, 0, 0, 0.5) !important;
}
.m_img{
    width: 16rpx;
    height: 24rpx;
}
.y_img{
    width: 23rpx;
    height: 24rpx;
}
.reduce{
    width: 0;
    height: 0;
    border-left: 10rpx solid transparent;
    border-top: 10rpx solid transparent;
    border-right: 10rpx solid #000;
    border-bottom: 10rpx solid transparent;
}
.reduce_dis{
    border-right: 10rpx solid #c8c8c8;
}
.add{
    border-left: 10rpx solid #000;
    border-right: 10rpx solid transparent;
}
.add_dis{
    border-left: 10rpx solid #c8c8c8; 
}
.days_item{
    display: block;
    width: 70rpx;
    height: 70rpx;
    text-align: center;
    line-height: 70rpx;
    border-radius: 50%;
}
.week-box{
    background-color: white;
    height: 600rpx;
}
.date-box{
    background-color: white;
}
.week_list{
    display: flex;
    justify-content: start;
    flex-wrap: wrap;
    overflow: scroll;
    max-height: 520rpx;
    margin-top: 10rpx;
}
.week-item{
    width: 33.3%;
    background: #fff;
    font-size: 26rpx;
    text-align: center;
    font-family: Source Han Sans SC;
    font-weight: 400;
    color: rgba(0,0,0, 0.8);
    margin: 15rpx 0;
}
.date-range{
    font-size: 20rpx;
}

js代码

// pages/common/datetime-picker/datetime-picker.js
let moment = require('../../../utils/moment.min');
let dayjs=require('../../../utils/dayjs.min')
import {chooseDateArea,cancelSelectedDates} from '../weekcalendar/main'
Component({
    /**
     * 组件的属性列表
     */
    properties: {
        selectPeriod:{
            type:String,
            value:'month'
        },
        selectDateShow:{
            type:Boolean,
            value:false
        },
        dateRange:{
            type:Array,
            value:[]
        }
    },

    /**
     * 组件的初始数据
     */
    data: {
        yearRes:moment().format("YYYY"),
        monthRes:moment().format("MM"),
        monthList:[
            {name:'1月',value:'01'},{name:'2月',value:'02'},{name:'3月',value:'03'},{name:'4月',value:'04'},
            {name:'5月',value:'05'},{name:'6月',value:'06'},{name:'7月',value:'07'},{name:'8月',value:'08'},
            {name:'9月',value:'09'},{name:'10月',value:'10'},{name:'11月',value:'11'},{name:'12月',value:'12'},
        ],
        startTime:'',
        endTime:'',
        dateName:'',
        calendarConfig:{
            defaultDay:moment().subtract(1, 'days').format('YYYY-MM-DD'),
            disableMode: {  // 禁用某一天之前/之后的所有日期
                type: 'after',  // [‘before’, 'after']
                date:moment(new Date()).day()==0?moment().format('YYYY-MM-DD'):moment().weekday(7).format("YYYY-MM-DD"), // 无该属性或该属性值为假,则默认为当天
                // date:false
              },
              chooseAreaMode:false,
              firstDayOfWeek: 'Mon',
        },
        weekData:[], //周日历数据
        weekRes:''
    },
    ready() {
        let tdM = this.getDateYMD().split('-')[1]*1;
        let mt = this.data.monthList;
        mt.forEach((m,i)=>{
            let mv = m.value*1;
            if(mv > tdM){
                m.avaliable = false;
            }else{
                m.avaliable = true;
            }
        })
        this.setData({
            monthList:mt
        })
    },
    /**
     * 组件的方法列表
     */
    methods: {
        getDateYMD(val){
            let date = null;
            if(val){
                date = new Date(val);
            }else{
                date = new Date();
            }
            
            let y = date.getFullYear();
            let m = date.getMonth() + 1;
            let d = date.getDate();
            let M,D;
            M = m<10?'0'+m:m;
            D = d<10?'0'+d:d;
            let today = y+'-'+M+'-'+D;
            return today;
        },
        // 
        whenChangeMonth(e){
          console.log(e)
        //   chooseDateArea([this.data.startTime,this.data.endTime]).then(dates => {
        //     console.log('choosed dates: ', dates);
        //   });
        },

        // 选择周日期回调
        afterTapDay(e){
            // this.setData({
            //     'calendarConfig.chooseAreaMode':false
            // })
            cancelSelectedDates()
            let year=e.detail.year
            let month=e.detail.month
            month=month<10?'0'+month:month
            let day=e.detail.day
            day=day<10?'0'+day:day
            let date=year+'-'+month+'-'+day
        //  let startTime = dayjs(date)
        //  .startOf("week")
        //  .format("YYYY-MM-DD");
        //  let endTime = dayjs(date)
        //  .endOf("week")
        //  .format("YYYY-MM-DD");
        //  console.log(startTime,endTime)
        let weekOfday = moment(date, "YYYY-MM-DD").format("E"); //计算今天是这周第几天
        let startTime = moment(date)
          .subtract(weekOfday - 1, "days")
          .format("YYYY-MM-DD"); //周一日期
        let endTime = moment(date).weekday(7).format("YYYY-MM-DD"); //周日日期
        // let endTime=moment().add(7-weekOfday-1, 'days').format('YYYY-MM-DD');
        if(moment(date).day()==0){
          endTime=date
        }
         this.setData({
             dateName:startTime+'到'+endTime,
             startTime:startTime,
             endTime:endTime
         })
         chooseDateArea([this.data.startTime,this.data.endTime]).then(dates => {
            console.log('choosed dates: ', dates);
          });
        },
        setWeek(date){
        //   let startTime = dayjs(date)
        //   .startOf("week")
        //   .format("YYYY-MM-DD");
        //   let endTime = dayjs(date)
        //   .endOf("week")
        //   .format("YYYY-MM-DD");
        let weekOfday = moment(date, "YYYY-MM-DD").format("E"); //计算今天是这周第几天
        let startTime = moment(date)
          .subtract(weekOfday - 1, "days")
          .format("YYYY-MM-DD"); //周一日期
        let endTime = moment(date).weekday(7).format("YYYY-MM-DD"); //周日日期
        // let endTime=moment().add(7-weekOfday-1, 'days').format('YYYY-MM-DD');
        // 解决日期在周日的计算结束时间不正确问题
        if(moment(date).day()==0){
            endTime=date
          }
         console.log(startTime,endTime)
         this.setData({
            dateName:startTime+'到'+endTime,
             startTime:startTime,
             endTime:endTime
         })
        },
        // 取消
        cancel(){
        this.setData({
            selectDateShow:false,
        })
        this.triggerEvent('closeDateDialog',{cancel:true})
        },
        // 选择周日期确认
        setlect_date(){
           if(!this.data.endTime){
           let yesterday=moment().subtract(1, 'days').format('YYYY-MM-DD');
           }
          this.triggerEvent('confirmWeekDate',{dateName:this.data.dateName,startTime:this.data.startTime,endTime:this.data.endTime})
        },
        // 减年份
        reduce(){
            if(Number(this.data.yearRes)==0){
                return
            }
            this.setData({
                yearRes:Number(this.data.yearRes)-1
            })
            if(this.data.selectPeriod=='week'){
                this.getWeekData(this.data.yearRes)
            }
        },
        // 加年份
        add(){
            if(Number(this.data.yearRes)==moment().format("YYYY")){
                return
            }
        this.setData({
            yearRes:Number(this.data.yearRes)+1
        })
        if(this.data.selectPeriod=='week'){
            this.getWeekData(this.data.yearRes)
        }
        },
        // 选择月份
        selectMonth(e){
            let item = e.currentTarget.dataset;
            if(item.cansel){
                this.setData({
                    monthRes:e.currentTarget.dataset.value
                })
            }
        },
        // 选择月份确认
        setlect_month_two(){
            let datetime=''
            if(this.data.selectPeriod=='year'){
             datetime=this.data.yearRes
            }
            if(this.data.selectPeriod=='month'){
            datetime=this.data.yearRes+'-'+this.data.monthRes
            }
           this.triggerEvent('submitYearMonth',{date:datetime})
        },
        // 获取指定日期在当年第几周
         getWeek(dt) {
            let d1 = new Date(dt);
            let d2 = new Date(dt);
            d2.setMonth(0);
            d2.setDate(1);
            let rq = d1 - d2;
            let days = Math.ceil(rq / (24 * 60 * 60 * 1000));
            let num = Math.ceil(days / 7);
            return num;
        },
        afterCalendarRender(e) {
            console.log('afterCalendarRender', e)
          },
        //   获取对应年的周日历数据
        getWeekData(year){
            const nowYear = year ? year : moment().year();
            console.log(typeof nowYear)
            const timestamp = (new Date()).valueOf()
                // 设置正在处理的年份
            let handleYear = moment(new Date(String(nowYear)));
              // 这一年有多少个周
            let totalWeeks = handleYear.endOf('year').isoWeek();
            const arryWeek  = [];
            let currentWeek = null; //当前日期是第几周
            totalWeeks++
            for(let i = 1;i <= totalWeeks;i++){
                let startOf = handleYear.week(i).startOf('week').format('MM-DD');
                let endOf = handleYear.week(i).endOf('week').format('MM-DD');
                let ednyear = handleYear.week(i).endOf('week').format('YYYY');
                let  startValue= handleYear.week(i).startOf('week').valueOf();
                let  endValue= handleYear.week(i).endOf('week').valueOf();
                if(startValue<=timestamp&&endValue>=timestamp){
                    currentWeek = i
                }
                arryWeek.push({
                    value: i-1,
                    name: `第${i-1}周`,
                    dates:`(${ednyear>nowYear?nowYear + "-" +startOf :startOf}/${ednyear>nowYear?ednyear + "-" +endOf:endOf})`,
                    startTime: handleYear.week(i).startOf('week').format('YYYY-MM-DD'),// 这周的开始时间
                    endTime: handleYear.week(i).endOf('week').format('YYYY-MM-DD'), // 这周的结束时间
                })
            } 
            this.setData({
                weekData:arryWeek,
                weekRes:currentWeek
            })
        },
        // 获取两个日期之间所有日期
        getDayAll(starDay, endDay) {
               let arr = [];
                let dates = [];
                // 设置两个日期UTC时间
            let db = new Date(starDay);
            let de = new Date(endDay);
            
                // 获取两个日期GTM时间
            let s = db.getTime() - 24 * 60 * 60 * 1000;
            let d = de.getTime() - 24 * 60 * 60 * 1000;
            
                // 获取到两个日期之间的每一天的毫秒数
               for (let i = s; i <= d;) {
                  i = i + 24 * 60 * 60 * 1000;
                    arr.push(parseInt(i))
               }
                
                // 获取每一天的时间  YY-MM-DD
                for( let j in arr ){
                    let time = new Date(arr[j]);
                    let year = time.getFullYear(time);
                    let mouth = (time.getMonth() + 1)>=10?(time.getMonth() + 1):('0'+(time.getMonth() + 1));
                    let day = time.getDate()>=10?time.getDate():('0'+time.getDate());
                    let YYMMDD = year + '-' + mouth + '-' + day;
                    dates.push(YYMMDD)
                }       
                return dates
            }
    },
    observers: {
       'selectDateShow':function(selectDateShow){
           if(selectDateShow&&this.data.selectPeriod=='week'){
               let date=moment().subtract(1, 'days').format('YYYY-MM-DD')
            this.setWeek(date)
           let dateArray= this.getDayAll(this.data.startTime,this.data.endTime)
            setTimeout(()=>{
                chooseDateArea([...this.data.dateRange]).then(dates => {
                    console.log('choosed dates: ', dates);
                  });
            },200)
           }
           if(selectDateShow&&this.data.selectPeriod=='month'){
            setTimeout(()=>{
                console.log(this.data.dateRange)
             this.setData({
                monthRes:this.data.dateRange[0]
             })
            },200)
           }
           if(selectDateShow&&this.data.selectPeriod=='year'){
            setTimeout(()=>{
                this.setData({
                    yearRes:this.data.dateRange[0]
                })
            },200)
           }
       } 
      }
})

json配置文件代码

{
    "component": true,
    "usingComponents": {
      "calendar": "../weekcalendar/index"
    }
  }

注意
这里是基于第三方日历组件进行二次封装的,需要在配置文件json中引入该组件,建议下载使用小历日历组件说明中的源码。
调用小历日历组件中的方法需要引入该组件中的main.js方法,例如:import {chooseDateArea,cancelSelectedDates} from '../weekcalendar/main'。

  • 实现效果
    周日历组件最后的效果:第一次触发日历组件会选中指定日期所在周的日期,当点击日历中的任何一个日期会选中点击日期所在周的所有日期,当用户确定改变周日期后会将周日期范围回显在页面上。

使用说明

  • 引入使用组件
    微信小程序引入组件和使用组件的方法这里不做过多说明,详情查微信小程序官方使用文档。
  • 组件属性和方法
    属性
参数说明类型默认值
selectDateShow用于控制周日历组件的显示和隐藏booleanfalse
selectPeriod选择的模式:周、月、年string''
dateRange回显的日期范围array[]

事件

事件名称说明回调函数
bindcloseDateDialog关闭日历组件的回调函数
bindconfirmWeekDate选择周日期的回调函数dateName:回显的日期范围名称,endTime:周日期范围的结束日期
最后修改:2022 年 10 月 25 日
如果觉得我的文章对你有用,请随意赞赏