微信小程序自定義可滑動日曆界面

找了好久的csdn博客,發現自定義的日曆控件很少,很多博主甚至不公開css代碼,只給了wxml和js。這本來就是一個學習的平臺,沒有必要藏着掖着。參考某個博主的自定義控件做了一些改動,希望這篇博客能幫助需要的人。

WXML

<view class='container'>
<view class='month flex m-around'>
    <view class='arrow' bindtap='prevMonth'>《 </view>
    <view class='year-and-month'>
        <picker mode="date" value="{{date}}" start="2015-09" end="2020-09" fields='month' bindchange="bindDateChange">
        <view>
            {{date}}
        </view>
        </picker>
    </view>
    <view class='arrow' bindtap='nextMonth'> 》</view>
</view>
<view class='calendar flex column s-center'>
  <view class='week-row flex m-around'>
    <view class='grid' wx:for="{{week}}" wx:key='item'>{{item}}</view>
  </view>
  <swiper class='swpier-box' circular="true" current="{{swiperIndex}}" bindchange='swiperChange'>
    <swiper-item class='flex m-around days-table '>
      <view wx:for="{{calendar.first}}" wx:for-item='x' wx:key='x.date'
        class='grid {{x.month === month?"":"notCurrent"}} {{x.date === today?"today":""}} {{x.date == beSelectDate ? "choice":""}}' data-month='{{x.month}}' data-day='{{x.day}}' data-date='{{x.date}}' bindtap='bindDayTap'>
        <view>{{x.date === today?'今天':x.day}}</view>
      </view>
    </swiper-item>
    <swiper-item class='flex m-around days-table '>
      <view wx:for="{{calendar.second}}" wx:for-item='x' wx:key='x.date'
        class='grid {{x.month === month?"":"notCurrent"}} {{x.date === today?"today":""}} {{x.date == beSelectDate ? "choice":""}}' data-month='{{x.month}}' data-day='{{x.day}}' data-date='{{x.date}}' data-test='{{(year + "-" +month + "-" + day)}}'  bindtap='bindDayTap'>
        <view>{{x.date === today?'今天':x.day}}</view>
      </view>
    </swiper-item>
    <swiper-item class='flex m-around days-table'>
      <view wx:for="{{calendar.third}}" wx:for-item='x' wx:key='x.date'
        class='grid {{x.month === month?"":"notCurrent"}} {{x.date === today?"today":""}} {{x.date == beSelectDate ? "choice":""}}' data-month='{{x.month}}' data-day='{{x.day}}' data-date='{{x.date}}' bindtap='bindDayTap'>
        <view>{{x.date === today?'今天':x.day}}</view>
      </view>
    </swiper-item>
    <swiper-item class='flex m-around days-table '>
      <view wx:for="{{calendar.fourth}}" wx:for-item='x' wx:key='x.date'
        class='grid {{x.month === month?"":"notCurrent"}} {{x.date === today?"today":""}} {{x.date == beSelectDate ? "choice":""}}' data-month='{{x.month}}' data-day='{{x.day}}' data-date='{{x.date}}' bindtap='bindDayTap'>
        <view>{{x.date === today?'今天':x.day}}</view>
      </view>
    </swiper-item>
  </swiper>
</view>
</view>

CSS

/* pages/calendar/calendar.wxss */
  .container {
  height: 100vh;

  background-color: #393E44;
}
.days-table {
  flex-wrap: wrap;
  align-content: flex-start;
}
.calendar{
  position: fixed;
  z-index:10000;
  background: #393E44;
  
}
.grid {
  width: 107.14rpx;
  height: 100rpx;
  text-align: center;
  line-height: 100rpx;
  font-size:.7rem;
  color:#fff;
}
.today {
  color: #88a1fd;
}
.grid view {
  height:85rpx;
  line-height: 85rpx;
  width:85rpx;
}
.choice view{
  border-radius: 50%;
  background: #88a1fd;
  background-position:center;
  color: white;
}
/* 非本月日期 */
.notCurrent {
  color: silver;
}
.day-hover {
  background: red;
}
.swpier-box {
  height: 550rpx;
  width: 100%;
}
.arrow {
  width: 100rpx;
  color: #88a1fd;
  text-align: center;
}
.year-and-month{
  color: #88a1fd;
}

.flex {
  display: flex;
}
/* 軸向 */
.column {
  flex-direction: column;
}
/* 主軸方向 */
.m-start {
  justify-content: flex-start;
}

.m-end {
  justify-content: flex-end;
}

.m-around {
  justify-content: space-around;
}
.m-between {
  justify-content: space-between;
}
.m-center {
  justify-content: center;
}
/* 側軸方向 */
.s-start {
  align-items: flex-start;
}
.s-end {
  align-items: flex-end;
}

.s-around {
  align-items: space-around;
}
.s-between {
  align-items: space-between;
}
.s-center {
  align-items: center;
}

JS

// pages/calendar/calendar.js

'use strict';

let choose_year = null,
  choose_month = null;
const conf = {
  data: {
    day: '',
    year: '',
    month: '',
    date: '2017-01',
    today: '',
    week: ['日', '一', '二', '三', '四', '五', '六'],
    calendar: {
      first: [],
      second: [],
      third: [],
      fourth: []
    },
    swiperMap: ['first', 'second', 'third', 'fourth'],
    swiperIndex: 1,
    showCaldenlar: false
  },
  onLoad() {
    const date = new Date()
      , month = this.formatMonth(date.getMonth() + 1)
      , year = date.getFullYear()
      , day = this.formatDay(date.getDate())
      , today = `${year}-${month}-${day}`
    let calendar = this.generateThreeMonths(year, month)

    this.setData({
      calendar,
      month,
      year,
      day,
      today,
      beSelectDate: today,
      date: `${year}-${month}`
    })
  },

  showCaldenlar() {
    this.setData({
      showCaldenlar: !this.data.showCaldenlar
    })
  },
	/**
	 * 
	 * 左右滑動
	 * @param {any} e 
	 */
  swiperChange(e) {
    const lastIndex = this.data.swiperIndex
      , currentIndex = e.detail.current
    let flag = false
      , { year, month, day, today, date, calendar, swiperMap } = this.data
      , change = swiperMap[(lastIndex + 2) % 4]
      , time = this.countMonth(year, month)
      , key = 'lastMonth'

    if (lastIndex > currentIndex) {
      lastIndex === 3 && currentIndex === 0
        ? flag = true
        : null
    } else {
      lastIndex === 0 && currentIndex === 3
        ? null
        : flag = true
    }
    if (flag) {
      key = 'nextMonth'
    }

    year = time[key].year
    month = time[key].month
    date = `${year}-${month}`
    day = ''
    if (today.indexOf(date) !== -1) {
      day = today.slice(-2)
    }

    time = this.countMonth(year, month)
    calendar[change] = null
    calendar[change] = this.generateAllDays(time[key].year, time[key].month)

    this.setData({
      swiperIndex: currentIndex,
      //文檔上不推薦這麼做,但是滑動並不會改變current的值,所以隨之而來的計算會出錯
      year,
      month,
      date,
      day,
      calendar
    })
  },
	/**
	 * 
	 * 點擊切換月份,生成本月視圖以及臨近兩個月的視圖
	 * @param {any} year 
	 * @param {any} month 
	 * @returns {object} calendar
	 */
  generateThreeMonths(year, month) {
    let { swiperIndex, swiperMap, calendar } = this.data
      , thisKey = swiperMap[swiperIndex]
      , lastKey = swiperMap[swiperIndex - 1 === -1 ? 3 : swiperIndex - 1]
      , nextKey = swiperMap[swiperIndex + 1 === 4 ? 0 : swiperIndex + 1]
      , time = this.countMonth(year, month)
    delete calendar[lastKey]
    calendar[lastKey] = this.generateAllDays(time.lastMonth.year, time.lastMonth.month)
    delete calendar[thisKey]
    calendar[thisKey] = this.generateAllDays(time.thisMonth.year, time.thisMonth.month)
    delete calendar[nextKey]
    calendar[nextKey] = this.generateAllDays(time.nextMonth.year, time.nextMonth.month)
    return calendar
  },
  bindDayTap(e) {
    let { month, year } = this.data
      , time = this.countMonth(year, month)
      , tapMon = e.currentTarget.dataset.month
      , day = e.currentTarget.dataset.day
    if (tapMon == time.lastMonth.month) {
      this.changeDate(time.lastMonth.year, time.lastMonth.month)
    } else if (tapMon == time.nextMonth.month) {
      this.changeDate(time.nextMonth.year, time.nextMonth.month)
    } else {
      this.setData({
        day
      })
    }
    let beSelectDate = e.currentTarget.dataset.date;
    this.setData({
      beSelectDate,
      showCaldenlar: false
    })
  },
  bindDateChange(e) {
    if (e.detail.value === this.data.date) {
      return
    }

    const month = e.detail.value.slice(-2)
      , year = e.detail.value.slice(0, 4)

    this.changeDate(year, month)
  },
  prevMonth(e) {
    let { year, month } = this.data
      , time = this.countMonth(year, month)
    this.changeDate(time.lastMonth.year, time.lastMonth.month)
  },
  nextMonth(e) {
    let { year, month } = this.data
      , time = this.countMonth(year, month)
    this.changeDate(time.nextMonth.year, time.nextMonth.month)
  },
	/**
	 * 
	 * 直接改變日期
	 * @param {any} year 
	 * @param {any} month 
	 */
  changeDate(year, month) {
    let { day, today } = this.data
      , calendar = this.generateThreeMonths(year, month)
      , date = `${year}-${month}`
    date.indexOf(today) === -1
      ? day = '01'
      : day = today.slice(-2)

    this.setData({
      calendar,
      day,
      date,
      month,
      year,
    })
  },
	/**
	 * 
	 * 月份處理
	 * @param {any} year 
	 * @param {any} month 
	 * @returns 
	 */
  countMonth(year, month) {
    let lastMonth = {
      month: this.formatMonth(parseInt(month) - 1)
    }
      , thisMonth = {
        year,
        month,
        num: this.getNumOfDays(year, month)
      }
      , nextMonth = {
        month: this.formatMonth(parseInt(month) + 1)
      }

    lastMonth.year = parseInt(month) === 1 && parseInt(lastMonth.month) === 12
      ? `${parseInt(year) - 1}`
      : year + ''
    lastMonth.num = this.getNumOfDays(lastMonth.year, lastMonth.month)
    nextMonth.year = parseInt(month) === 12 && parseInt(nextMonth.month) === 1
      ? `${parseInt(year) + 1}`
      : year + ''
    nextMonth.num = this.getNumOfDays(nextMonth.year, nextMonth.month)
    return {
      lastMonth,
      thisMonth,
      nextMonth
    }
  },
  currentMonthDays(year, month) {
    const numOfDays = this.getNumOfDays(year, month)
    return this.generateDays(year, month, numOfDays)
  },
	/**
	 * 生成上個月應顯示的天
	 * @param {any} year 
	 * @param {any} month 
	 * @returns 
	 */
  lastMonthDays(year, month) {
    const lastMonth = this.formatMonth(parseInt(month) - 1)
      , lastMonthYear = parseInt(month) === 1 && parseInt(lastMonth) === 12
        ? `${parseInt(year) - 1}`
        : year
      , lastNum = this.getNumOfDays(lastMonthYear, lastMonth) //上月天數
    let startWeek = this.getWeekOfDate(year, month - 1, 1) //本月1號是周幾
      , days = []
    if (startWeek == 7) {
      return days
    }

    const startDay = lastNum - startWeek

    return this.generateDays(lastMonthYear, lastMonth, lastNum, { startNum: startDay, notCurrent: true })
  },
	/**
	 * 生成下個月應顯示天
	 * @param {any} year 
	 * @param {any} month
	 * @returns 
	 */
  nextMonthDays(year, month) {
    const nextMonth = this.formatMonth(parseInt(month) + 1)
      , nextMonthYear = parseInt(month) === 12 && parseInt(nextMonth) === 1
        ? `${parseInt(year) + 1}`
        : year
      , nextNum = this.getNumOfDays(nextMonthYear, nextMonth)  //下月天數
    let endWeek = this.getWeekOfDate(year, month)						 //本月最後一天是周幾
      , days = []
      , daysNum = 0
    if (endWeek == 6) {
      return days
    } else if (endWeek == 7) {
      daysNum = 6
    } else {
      daysNum = 6 - endWeek
    }
    return this.generateDays(nextMonthYear, nextMonth, daysNum, { startNum: 1, notCurrent: true })
  },
	/**
	 * 
	 * 生成一個月的日曆
	 * @param {any} year 
	 * @param {any} month 
	 * @returns Array
	 */
  generateAllDays(year, month) {
    let lastMonth = this.lastMonthDays(year, month)
      , thisMonth = this.currentMonthDays(year, month)
      , nextMonth = this.nextMonthDays(year, month)
      , days = [].concat(lastMonth, thisMonth, nextMonth)
    return days
  },
	/**
	 * 
	 * 生成日詳情
	 * @param {any} year 
	 * @param {any} month 
	 * @param {any} daysNum 
	 * @param {boolean} [option={
	 * 		startNum:1,
	 * 		grey: false
	 * 	}] 
	 * @returns Array 日期對象數組
	 */
  generateDays(year, month, daysNum, option = {
    startNum: 1,
    notCurrent: false
  }) {
    const weekMap = ['一', '二', '三', '四', '五', '六', '日']
    let days = []
    for (let i = option.startNum; i <= daysNum; i++) {
      let week = weekMap[new Date(year, month - 1, i).getUTCDay()]
      let day = this.formatDay(i)
      days.push({
        date: `${year}-${month}-${day}`,
        event: false,
        day,
        week,
        month,
        year
      })
    }
    return days
  },
	/**
	 * 
	 * 獲取指定月第n天是周幾		|
	 * 9月第1天: 2017, 08, 1 |
	 * 9月第31天:2017, 09, 0 
	 * @param {any} year 
	 * @param {any} month 
	 * @param {number} [day=0] 0爲最後一天,1爲第一天
	 * @returns number 周 1-7, 
	 */
  getWeekOfDate(year, month, day = 0) {
    let dateOfMonth = new Date(year, month, 0).getUTCDay() + 1;
    dateOfMonth == 7 ? dateOfMonth = 0 : '';
    return dateOfMonth;
  },
	/**
	 * 
	 * 獲取本月天數
	 * @param {number} year 
	 * @param {number} month 
	 * @param {number} [day=0] 0爲本月0最後一天的
	 * @returns number 1-31
	 */
  getNumOfDays(year, month, day = 0) {
    return new Date(year, month, day).getDate()
  },
	/**
	 * 
	 * 月份處理
	 * @param {number} month 
	 * @returns format month MM 1-12
	 */
  formatMonth(month) {
    let monthStr = ''
    if (month > 12 || month < 1) {
      monthStr = Math.abs(month - 12) + ''
    } else {
      monthStr = month + ''
    }
    monthStr = `${monthStr.length > 1 ? '' : '0'}${monthStr}`
    return monthStr
  },
  formatDay(day) {
    return `${(day + '').length > 1 ? '' : '0'}${day}`
  }
}
Page(conf)

效果圖
在這裏插入圖片描述

每天進步一點點,開心也多一點點

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