微信小程序自定義組件---日曆打卡組件

最近需求要求實現一個用日曆顯示用戶打卡記錄的功能,百度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" }
      ],
    })
  },

完整代碼:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章