因爲解決不了vant日曆組件動態渲染formatter的問題,於是自己擼了一個簡易的小程序日曆組件

 

代碼倉庫地址:https://github.com/imxiaoer/WeChatMiniCalendar

 

一、效果圖如下:

 

 

二、業務場景介紹

客戶原始需求:用戶需要知道在選中的月份中,哪些日期是有客戶預約的,並且顯示當天預約人數,點擊有預約的日期則進入預約信息詳細頁,詳細頁內可以新建預約;點擊沒有預約的日期則直接進入新建預約頁面。

 

三、需求實現

因爲項目用的是vant的小程序ui組件,所以剛開始想的是用vant的日曆組件來實現此需求。經過幾番嘗試後,始終實現不了 formatter 的動態數據渲染,最後放棄了(如有大佬已實現此功能,麻煩留言分享下你的解決方案,謝謝),然後自己寫了一個日曆組件。

 

主要功能:

1.  根據傳入的日期,渲染當月日曆,如傳入 2021/6/1,則渲染2021年6月份的日曆

2. 點擊單個日期,返回具體年月日,並且被點擊日期變色

3. 根據用戶數據,動態渲染日曆標註。傳入的日期變更,或者是用戶數據變更,都會重新渲染日曆及標註。上面效果圖下方的【改日期】和 【改數據】就是用來測試這個功能的。

 

 

四、主要代碼

 

1.  calendar.wxml

<view class="calendar-box">
  <view class="head-box">
    <view class="title-box">{{title}}</view>
    <view class="week-box">
      <view class="week-item"></view>
      <view class="week-item"></view>
      <view class="week-item"></view>
      <view class="week-item"></view>
      <view class="week-item"></view>
      <view class="week-item"></view>
      <view class="week-item"></view>
    </view>
  </view>
  <view class="date-box">
    <view
      bindtap="clickItem"
      data-date="{{day.date}}"
      class="date-item {{currentDate == day.date ? 'active' : ''}}"
      wx:for="{{daysArray}}" wx:for-item="day"
      wx:key="index">
      <view class="top-text" wx:if="{{day.topText}}">{{day.topText}}</view>
      {{day.date}}
      <view class="bottom-text" wx:if="{{day.bottomText}}">{{day.bottomText}}</view>
    </view>
  </view>
</view>

 

2. calendar.js

// components/calendar/calendar.js
Component({
  /**
   * 組件的屬性列表
   */
  properties: {
    defaultDate: {
      type: String,
      observer () {
        this.getCurrentDaysAndWeekStart();
        this.renderDate();
        this.triggerEvent('formatter', this.data.daysArray);
      }
    },
    isDataChange: {
      type: Boolean,
      value: false,
      observer () {
        this.triggerEvent('formatter', this.data.daysArray);
      }
    },
    daysData: {
      type: Array,
      observer (newVal) {
        if (newVal.length > 0) {
          this.setData({ daysArray: newVal });
        }
      }
    }
  },

  /**
   * 組件的初始數據
   */
  data: {
    Y: '', //
    M: '', //
    D: '', //
    W: '', // 星期
    firstDayWeek: '', // 當前月第一天星期幾
    lastDayWeek: '',  // 當前月最後一天星期幾
    daysCount: 0,  // 總天數
    daysArray: [], // 日曆中天數數組
    title: '',
    currentDate: '0'
  },

  /**
   * 組件的方法列表
   */
  methods: {
    // 獲取當前月的天數,以及當前月第一天是星期幾,最後一天是星期幾
    getCurrentDaysAndWeekStart () {
      let dateString = this.properties.defaultDate;
      let today = new Date();
      if (dateString) {
        today = new Date(dateString);
      }
      let Y = today.getFullYear();
      let M = today.getMonth() + 1;
      let D = today.getDate();
      let daysCount = new Date(Y, M, 0).getDate(); // 當前月最後一天日期,即當前月的天數
      let firstDayWeek = new Date(Y, M - 1, 1).getDay(); // 第一天星期幾
      let lastDayWeek = new Date(Y, M, 0).getDay(); // 最後一天星期幾
      this.setData({
        Y: Y,
        M: M,
        D: D,
        firstDayWeek: firstDayWeek,
        lastDayWeek: lastDayWeek,
        daysCount: daysCount,
        title: `${Y}年${M}月`
      });
    },

    // 根據總天數和第一天星期幾,最後一天星期幾,渲染日曆天數數組
    renderDate () {
      let firstDayWeek = this.data.firstDayWeek;
      let lastDayWeek = this.data.lastDayWeek;
      let daysCount = this.data.daysCount;
      let days = []; // 當前月總天數數組
      for (let i = 1; i <= daysCount; i++) {
        days.push({
          date: i.toString(),
          topText: '',
          bottomText: ''
        });
      }
      
      // 補全前面 (因爲一週七天,如果第一天是星期三,則需要把星期一和星期二數據補全)
      for (let i = 0; i < firstDayWeek; i++) {
        days.unshift({
          date: '',
          topText: '',
          bottomText: ''
        });
      }
      
      // 補全後面 (因爲一週七天,如果最後一天是星期五,則需要把星期六和星期天數據補全)
      for (let i = lastDayWeek; i <= 7; i++) {
        days.push({
          date: '',
          topText: '',
          bottomText: ''
        });
      }

      this.setData({ daysArray: days });
    },

    // 點擊單個日期事件
    clickItem (event) {
      let date = event.currentTarget.dataset.date;
      if (date) {
        this.setData({ currentDate: date });
        this.triggerEvent('select', `${this.data.Y}-${this.data.M}-${date}`);
      }
    }
  }
})

 

 

3. calendar.wxss

/* components/calendar/calendar.wxss */
.calendar-box {
  background-color: #ffffff;
  padding: 10rpx;
  color: #323233;
}
.head-box {
  box-shadow: 0 2px 10px rgb(125 126 128 / 16%);
}
.title-box {
  padding: 20rpx 0 40rpx 0;
  text-align: center;
  font-size: 14px;
}
.week-box {
  display: flex;
  justify-content: space-between;
  font-size: 12px;
  padding-bottom: 20rpx;
}
.week-item {
  width: 100%;
  text-align: center;
}
.date-box {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
}
.date-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 125rpx;
  width: 14.285%;
  border-radius: 10rpx;
  font-size: 12px;
}
.top-text, .bottom-text {
  font-size: 8px;
  color: red;
}
.active {
  background-color: pink;
}

 

因爲網絡的原因,打不開github,所以暫時沒法上傳demo代碼,之後代碼上傳到GitHub了會在文章頂部貼出地址,謝謝關注。

 

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