通过下面截图能够看出

  1. 点击上月和下月切换月份
  2. 点击具体的日期能够在页面上显示选中日期
  3. 点击确定将会取得选中日期
  4. 点击灰色的日期能够跳转对应月份并高亮日期

构造

日历构造次要分为 mask 和 calender

  • 代码

    <view class="mask {{show ? 'show' : ''}}" catch:tap="onClickMask"></view><view class="calender {{onceShow ? 'show' : ''}} {{show ? 'enter' : 'leave'}}">  <view class="header">    <view class="header-title">      <view catch:tap="onToggleMonthClick" data-type="prev">上月</view>      <view class="title">{{year}}年{{month+1}}月</view>      <view catch:tap="onToggleMonthClick" data-type="next">下月</view>    </view>        <!-- 星期 -->    <view class="weekdays">      <view class="weekday">日</view>      <view class="weekday">一</view>      <view class="weekday">二</view>      <view class="weekday">三</view>      <view class="weekday">四</view>      <view class="weekday">五</view>      <view class="weekday">六</view>    </view>  </view>  <view class="body">    <view class="month">            <!-- 日期 -->      <view class="dates">        <block wx:for="{{thisMonthDates}}" wx:key="*this">          <view              class="date {{item.isToday ? 'today' :''}} {{item.isSelectedDate ? 'selected-date' : ''}} {{item.isEmptyDate ? 'empty-date' : ''}}"              data-index="{{index}}"              data-type="{{item.monthState}}"              data-formatDate="{{item.formatDate}}"              catch:tap="onSelectDateClick"          >{{item.date}}          </view>        </block>      </view>    </view>    <view class="footer">确定</view>  </view></view>

mask 是遮罩层,当日历弹出时,显示在日历前面,calender 之所以没有放在外面,是因为组件弹出时须要做动画,组件显示的时候 mask 须要立刻呈现。

calender 分为有两种操作

  • 上月和下月切换
  • 日期点击高亮

依据日历构造,写出日历款式

  • 日期的款式分为以后月、上月、下月,上月下月为灰色
  • 高亮当天
  • 切换日期时,当天的色彩是金色
  • 款式代码

外围代码

日历组件最重要的是如何计算当月多少天,以及对应星期几。

好在 js 提供了 new Date().getDate() 能够获取明天是几号,Date 可承受 3 个参数 year、month、date,如果 date 大于这个月的最大天数,就会主动换算成下个月的几号,同理如何小于 1 号,就会主动换算出上个月的几号。利用这个个性,date 传递 0 进去就能晓得有多少天了。

new Date(2020, 5, 2).getDate()   // 2new Date(2020, 5, 1).getDate()   // 1new Date(2020, 5, 0).getDate()   // 31

通过 new Date().getDay() 能够获取 date 是星期几,它的值是 0~6,正好能够用 0 代表星期日。

  • 代码

    getThisDateWeek({year, month, date}: YearMonthDate) {  return new Date(Date.UTC(year, month, date)).getDay()},getThisMonthDays(year: number, month: number) {  return new Date(year, month + 1, 0).getDate()}

晓得了当月多少天,怎么晓得当月后面和前面有多少天呢?

  • 代码

    methods: {    // 当月    createDays() {      const thisMonthDates: any[] = []      const {year, month} = this.data      const thisMonthTotalDate = this.getThisMonthDays(year, month)      for (let date = 1; date <= thisMonthTotalDate; date++) {        const monthGrid = this.formatMonthGrid({year, month, date})        thisMonthDates.push(monthGrid)      }      this.data.thisMonthDates = thisMonthDates      this.setData({thisMonthTotalDate})    },    // 单月的上月和下月有多少天    createEmptyDays() {    let {year, month, thisMonthDates} = this.data        // 当月第一天是星期几    const firstDayWeek = this.getThisDateWeek({year, month, date: 1})    const emptyGridsBefore = this.getBeforeMonthEmpty(firstDayWeek)    const emptyGridsAfter = this.getAfterMonthEmpty(firstDayWeek)    thisMonthDates = [...emptyGridsBefore, ...thisMonthDates, ...emptyGridsAfter]    this.setData({thisMonthDates})  },        // 上月    getBeforeMonthEmpty(firstDayWeek: number) {    const {year, month} = this.data    const emptyGridsBefore: any[] = []    const {prevYear, prevMonth} = this.prevYear(year, month)    const prevMonthDay = this.getThisMonthDays(year, prevMonth)        // 上月 补满 1 号后面的日期    for (let i = 1; i <= firstDayWeek; i++) {      const date = prevMonthDay - (firstDayWeek - i)      const monthGrid = this.formatMonthGrid({year: prevYear, month: prevMonth, date}, MonthState.Prev)      emptyGridsBefore.push(monthGrid)    }    return emptyGridsBefore  },    // 下月  getAfterMonthEmpty(firstDayWeek: number) {    const emptyGridsAfter: any[] = []    const {thisMonthTotalDate, year, month} = this.data    const {nextYear, nextMonth} = this.nextYear(year, month)        // 日期默认显示 42 天,-7 是为了如果 35 天能显示全的话就用 35 天    const nextMonthDay = 42 - thisMonthTotalDate - firstDayWeek - 7 >= 0 ?        42 - thisMonthTotalDate - firstDayWeek - 7 :        42 - thisMonthTotalDate - firstDayWeek                // 下月补满当月最初一天前面的日期    for (let date = 1; date <= nextMonthDay; date++) {      const monthGrid = this.formatMonthGrid({year: nextYear, month: nextMonth, date}, MonthState.Next)      emptyGridsAfter.push(monthGrid)    }    return emptyGridsAfter  },    // 如果是 1 月,上月就是上年 12 月    prevYear(year: number, month: number) {    const prevYear = month === 0 ? year - 1 : year    const prevMonth = month === 0 ? 11 : month - 1    return {prevYear, prevMonth}  },    // 如果是 12 月,下月就是下年 1月  nextYear(year: number, month: number) {    const nextYear = month === 11 ? year + 1 : year    const nextMonth = month === 11 ? 0 : month + 1    return {nextYear, nextMonth}  },}

性能代码

  • 代码

    methods: {    // state 是用来判断上月还是下月    formatMonthGrid({year, month, date}: YearMonthDate, state?: string) {      const formatDate = this.formatDate({year, month, date})      const isSelectedDate = this.defaultSelectedDateGrid(formatDate, state)      const isEmptyDate = this.isEmptyDateGrid(month)      const week = this.getThisDateWeek({year, month, date})      const isToday = this.isToday(formatDate)      return {        year,        month,        date,        formatDate,        week,        isSelectedDate,        isEmptyDate,        isToday,        monthState: state      }    },    // 点击日期高亮    setSelectedDateGrid(formatDate: string) {      const {thisMonthDates} = this.data      let selectedDate: string = ''      thisMonthDates.forEach((thisMonthDate: any) => {        if (thisMonthDate.formatDate === formatDate) {          thisMonthDate.isSelectedDate = true          selectedDate = thisMonthDate.formatDate        } else {          thisMonthDate.isSelectedDate = false        }      })      this.data.selectedDate = selectedDate      this.setData({thisMonthDates})    },    // 默认日期高亮    defaultSelectedDateGrid(formatDate: string, state: string) {      const {selectedDate} = this.data      // 只高亮当月,上月和下月的不高亮      return formatDate === selectedDate && !state    },        // 明天    isToday(formatDate: string) {      const {value} = this.data      return value === formatDate    },        // 是不是当月    isEmptyDateGrid(month: number) {      const {month: thisMonth} = this.data      return month !== thisMonth    },        formatDate({year, month, date}: YearMonthDate) {      return `${year}-${month + 1}-${date}`    },}

事件

  • 代码

    methods: {    onSelectDateClick(e: Event) {      const {formatdate, type} = e.currentTarget.dataset      const {selectedDate} = this.data      if (formatdate === selectedDate) return      this.toggleMonth(type)      this.setSelectedDateGrid(formatdate)    },        // 上月和下月切换    onToggleMonthClick(e: Event) {      const {type} = e.currentTarget.dataset      this.toggleMonth(type)    },    toggleMonth(type: string) {      if (type === MonthState.Prev) {        this.prevMonth()      } else if (type === MonthState.Next) {        this.nextMonth()      }    },    prevMonth() {      const {year, month} = this.data      const {prevYear, prevMonth} = this.prevYear(year, month)      this.setData({year: prevYear, month: prevMonth}, () => {        this.createDays()        this.createEmptyDays()      })    },    nextMonth() {      const {year, month} = this.data      const {nextYear, nextMonth} = this.nextYear(year, month)      this.setData({year: nextYear, month: nextMonth}, () => {        this.createDays()        this.createEmptyDays()      })    },}

Properties

  • 代码

    properties = {  show: {    type: Boolean,    value: false,    observer(show: boolean) {      if (show)        this.setData({enter: show, onceShow: true})    }  },  value: {    type: String,    value: '-1',    observer(value: string) {      // 2020-6-15      const year = +(value.split("-")[0])      const month = +(value.split("-")[1]) - 1      const date = +(value.split("-")[2])      this.data.selectedDate = value      this.setData({year, month, date}, () => {        this.initDate()        this.createDays()        this.createEmptyDays()      })    }  }},methods = {    initDate() {        let {year, month, date} = this.data        if (year && month && date) return        year = new Date().getFullYear()        month = new Date().getMonth()        date = new Date().getDate()        this.data.selectedDate = this.formatDate({year, month, date})        this.setData({year, month, date})    },    onClickMask() {        this.setData({show: false, value: '-1'})    },}