微信小程序自定义组件---日历打卡组件

最近需求要求实现一个用日历显示用户打卡记录的功能,百度google了微信小程序的组件,都没有找到合适的,索性就懒得找了,自己动手,丰衣足食。

下面先来看看日历组件的效果吧:

设计要求:

1、能够折叠日历组件

2、能够标记日期

3、能够根据左右滑动切换月份,并且刷新数据。

 

设计思路:

1、折叠可以通过添加移除class实现动画折叠。

2、每个日期都是一个格子,可以放时间,也可以放图标,只需要根据wx:if来控制是否显示图标和样式。

3、使用微信的原生组件swiper来实现左右滑动的效果,监听swiper切换并刷新数据。

 

组件代码如下:

index.js

Component({
  properties: {
    clockDatas: {
      type: Array
    }
  },
  data: {
    showMore: false,
    weekData: ['日', '一', '二', '三', '四', '五', '六'],
    miniContent: [
      ///monthStatus:0-上月日期,1-本月日期,2-下月日期,isSignIn是否已签到,isToday当前日期是否是今天
      { id: 1, title: "26", monthStatus: 1, isSignIn: false, isToday: false }
    ],
    largeContent: [],
    today: "",
    currentYear: "",
    currentMonth: "",
    currentDate: "",
    lastSwiper: 0
  },
  observers: {
    'clockDatas': function(data){
      console.log("数据更新");
      let changeDate = this.data.currentYear + "-" + this.data.currentMonth + "-1";
      this.getLargeDate(changeDate);
    }
  },
  ready: function () {
    this.initCalendar();
  },
  methods: {
    contentToggle(){
      this.setData({
      showMore: !this.data.showMore
      })
    },
    //初始化日历
    initCalendar(){
      let dateObject = new Date(),
        year = dateObject.getFullYear(),
        month = dateObject.getMonth() + 1,
        date = dateObject.getDate(),
        today = year + '-' + this.zero(month) + '-' + this.zero(date);

      this.setData({
        today: today,
        currentYear: year,
        currentMonth: month,
        currentDate: date
      });

      this.getMiniDate();
      this.getLargeDate();
    },

    // 获取小日期
    getMiniDate(){
      let dateObject = new Date();
      let toMonth = dateObject.getMonth() + 1;
      let toDay = dateObject.getDate();
      let toWeek = dateObject.getDay();
      dateObject.setDate(dateObject.getDate() - toWeek);
      let miniData = [];
      for(let i=0;i<7;i++){
        let currentDate = this.getFormatDate(dateObject);
        let clockDate = this.data.clockDatas.filter((item) => item.date==currentDate.date);
        let currentObj = {
          title: currentDate.day,
          monthStatus: (currentDate.month > toMonth ? 2 : (currentDate.month < toMonth ? 0 : 1)),
          isSignIn: clockDate.length>0?true:false,
          isToday: (currentDate.day==toDay ? true : false)
        }
        miniData.push(currentObj);
        dateObject.setDate(dateObject.getDate()+1);
      }

      //console.log("小日期", miniData);
      this.setData({
        miniContent: miniData
      });
    },

    // 获取大的日期
    getLargeDate(dates){
      let dateObject = dates ? new Date(dates) : new Date();
      let toMonth = dateObject.getMonth() + 1;
      let toDay = dateObject.getDate();
      let toWeek = new Date(dateObject.getFullYear(), toMonth - 1, 1).getDay(); // 获取本月一号的星期
      let toDates = 42;
      dateObject.setDate(dateObject.getDate() - (toWeek + toDay - 1));
      let largeData = [];
      for (let i = 0; i < toDates; i++) {
        let currentDate = this.getFormatDate(dateObject);
        let clockDate = this.data.clockDatas.filter((item) => item.date==currentDate.date);
        let currentObj = {
          title: currentDate.day,
          monthStatus: (currentDate.month > toMonth ? 2 : (currentDate.month < toMonth ? 0 : 1)),
          isSignIn: clockDate.length>0?true:false,
          isToday: (currentDate.date == this.data.today ? true : false)
        }
        largeData.push(currentObj);
        dateObject.setDate(dateObject.getDate() + 1);
      }
      //console.log("大日期", largeData);
      this.setData({
        largeContent: largeData
      });
    },

    getFormatDate(date){
      let year = date.getFullYear(),
        month = date.getMonth() + 1,
        day = date.getDate();
      let currentDate = year + "-" + this.zero(month) + "-" + this.zero(day);
      return {
        year: year,
        month: month,
        day: day,
        date: currentDate
      }
    },

    // 滑块改变事件
    swiperChange(e){
      let current = e.detail.current;
      let lastSwiper = this.data.lastSwiper;
      let status = current - lastSwiper;
      if(status == -1 || status == 2){
        //console.log("右滑");
        this.setCurrentDate(0); //月份减一
      }else if(status == 1 || status == -2){
        //console.log("左滑");
        this.setCurrentDate(1); //月份加一
      }else{
        console.log("其他");
      }

      let changeDate = this.data.currentYear + "-" + this.data.currentMonth + "-1";
      //this.getLargeDate(changeDate);
      this.triggerEvent('changeMonth',{year: this.data.currentYear, month: this.data.currentMonth});


      this.setData({
        lastSwiper: current
      })
    },

    // 根据传入的参数加减月份
    setCurrentDate(type){
      let currentYear = Number(this.data.currentYear);
      let currentMonth = Number(this.data.currentMonth);
      if(type){
        if(currentMonth==12){
          currentYear = currentYear + 1;
          currentMonth = 1;
        }else{
          currentMonth = currentMonth + 1;
        }
      }else{
        if(currentMonth == 1){
          currentYear = currentYear - 1;
          currentMonth = 12;
        }else{
          currentMonth = currentMonth - 1;
        }
      }

      this.setData({
        currentYear: currentYear,
        currentMonth: currentMonth
      })

    },

    //补全0
    zero: function (i) {
      return i >= 10 ? i : '0' + i;
    },
  }
})

index.wxml

<view class="calendar">
  <view class="week-container">
    <block wx:for="{{weekData}}">
      <view class="week-item">{{item}}</view>
    </block>
  </view>

  <view class="calendar-container {{showMore?'large-active':''}}">
    <block wx:if="{{!showMore}}">
      <view class="mini-calendar">
        <block wx:for="{{miniContent}}">
          <view class="day-item {{item.monthStatus==1?'':'other-moth'}}">
            <view class="day-title {{item.isSignIn?'sign-active':''}} {{item.isToday?'today':''}}">
              {{item.title}}
            </view>
            <view wx:if="{{item.isSignIn}}" class="sign-icon">
              <image class="image" src="../../images/clockin_ok.png"></image>
            </view>
          </view>
        </block>
      </view>
    </block>
    <block wx:elif="{{showMore}}">
      <swiper class="swiper" circular bindchange="swiperChange">
          <!-- 第一滑块 -->
          <swiper-item>
            <view class="large-calendar">
              <block wx:for="{{largeContent}}">
                <view class="day-item {{item.monthStatus==1?'':'other-moth'}}">
                  <view class="day-title {{item.isSignIn?'sign-active':''}} {{item.isToday?'today':''}}">{{item.title}}</view>
                  <view wx:if="{{item.isSignIn}}" class="sign-icon">
                    <image class="image" src="../../images/clockin_ok.png"></image>
                  </view>
                </view>
              </block>

              <view class="month-show">
                <text>{{currentYear}}年 {{currentMonth}}月</text>
              </view>
            </view>
          </swiper-item>
          <!-- 第二滑块 -->
          <swiper-item>
            <view class="large-calendar">
              <block wx:for="{{largeContent}}">
                <view class="day-item {{item.monthStatus==1?'':'other-moth'}}">
                  <view class="day-title {{item.isSignIn?'sign-active':''}} {{item.isToday?'today':''}}">{{item.title}}</view>
                  <view wx:if="{{item.isSignIn}}" class="sign-icon">
                    <image class="image" src="../../images/clockin_ok.png"></image>
                  </view>
                </view>
              </block>

              <view class="month-show">
                <text>{{currentYear}}年 {{currentMonth}}月</text>
              </view>
            </view>
          </swiper-item>
          <!-- 第三滑块 -->
          <swiper-item>
            <view class="large-calendar">
              <block wx:for="{{largeContent}}">
                <view class="day-item {{item.monthStatus==1?'':'other-moth'}}">
                  <view class="day-title {{item.isSignIn?'sign-active':''}} {{item.isToday?'today':''}}">{{item.title}}</view>
                  <view wx:if="{{item.isSignIn}}" class="sign-icon">
                    <image class="image" src="../../images/clockin_ok.png"></image>
                  </view>
                </view>
              </block>

              <view class="month-show">
                <text>{{currentYear}}年 {{currentMonth}}月</text>
              </view>
            </view>
          </swiper-item>
      </swiper>
    </block>
    
    <view class="bottom-toggle">
      <view class="toggle-content" bindtap="contentToggle">
        <view class="toggle-left"></view>
        <view class="toggle-center">
          <text class="iconfont {{showMore?'iconicon-test1':'iconicon-test3'}}"></text>
        </view>
        <view class="toggle-right"></view>
      </view>
    </view>
  </view>
</view>

index.wxss

@import "../../utils/iconfont.wxss";
.calendar {
  width: 100%;
  text-align: center;
  font-size: 28rpx;
  padding: 0rpx 20rpx;
  background:  linear-gradient(to bottom, #ff6000, #ffbb59);
  box-shadow: 0 0 3px #ccc;
}

/* 星期头部 */
.week-container{
  width: 100%;
  padding: 10rpx 0rpx;
  display: flex;
  align-items: center;
  justify-content: space-around;
  color: #ffffff;
}
.week-container .week-item{
  flex: 1;
  width: 100rpx;
  text-align: center;
}
/* 星期头部 */

/* 主体 */
.calendar-container{
  width: 100%;
  height: 120rpx;
  transition: all .25s;
  position: relative;
}
.large-active{
  height: 780rpx;
}
.bottom-toggle{
  width: 100%;
  height: 30rpx;
  line-height: 30rpx;
  position: absolute;
  bottom: -30rpx;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  z-index: 9;
}
.bottom-toggle .toggle-content{
  height: 30rpx;
  width: 108rpx;
  text-align: center;
  position: relative;
}
.bottom-toggle .toggle-content .toggle-left{
  width: 20rpx;
  height: 40rpx;
  transform: rotate(-30deg);
  background-color: #ffbb59;
  position: absolute;
  left: -14rpx;
  top: -12rpx;
}
.bottom-toggle .toggle-content .toggle-center{
  width: 100%;
  height: 100%;
  color: #ffffff;
  background-color: #ffbb59;
  font-size: 42rpx;
  line-height: 24rpx;
  text-align: center;
}
.bottom-toggle .toggle-content .toggle-right{
  width: 20rpx;
  height: 40rpx;
  transform: rotate(30deg);
  background-color: #ffbb59;
  position: absolute;
  right: -14rpx;
  top: -12rpx;
}
/* 主体 */

/* 收缩日历主体 */
.mini-calendar{
  display: flex;
  align-items: center;
  justify-content: space-around;
  color: #ffffff;
}
/* 收缩日历主体 */

/* 展开日历主体 */
.swiper{
  height: 780rpx;
}
.large-calendar{
  display: flex;
  align-items: center;
  justify-content: space-around;
  flex-wrap: wrap;
  color: #ffffff;
}
.large-calendar .month-show{
  width: 100%;
  height: 60rpx;
  text-align: center;
  color: #ffffff;
}
/* 展开日历主体 */

/* 公用样式 */
.day-item{
  flex-shrink: 0;
  width: 100rpx;
  min-height: 100rpx;
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  margin-bottom: 20rpx;
}
.other-moth{
  color: #e2e2e2;
}
.today-item{
  position: absolute;
  width: 20rpx;
  height: 20rpx;
  border-radius: 50%;
}
.day-item .day-title{
  width: 50rpx;
  height: 50rpx;
  line-height: 50rpx;
  border-radius: 50%;
}
.day-item .sign-active{
  background-color: rgba(255,255,255,0.3);
}
.day-item .today{
  background-color: #ff6000;
}
.day-item .sign-icon{
  width: 40rpx;
  height: 40rpx;
  margin-top: 10rpx;
}
.day-item .sign-icon .image{
  width: 100%;
  height: 100%;
}
/* 公用样式 */

 

父组件使用方法:

// wxml
<rwj-calendar clock-datas="{{clockData}}" bindchangeMonth="changeMonth"></rwj-calendar>


// js

  data: {
    clockData: [
      { date: "2020-06-01" },
      { date: "2020-06-02" },
      { date: "2020-06-03" },
      { date: "2020-06-04" }
    ],
  },

  // 日历组件月更改事件
  changeMonth(e){
    console.log("日历组件月改变事件",e);

    this.setData({
      clockData: [
        { date: "2020-05-11" },
        { date: "2020-05-12" },
        { date: "2020-05-23" },
        { date: "2020-05-24" }
      ],
    })
  },

完整代码:https://download.csdn.net/download/qq_41756580/12827602

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

专业前端小白

写了这么久文章,1分钱都没收到

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

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

打赏作者

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

抵扣说明:

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

余额充值