通过上面截图可以看出
- 点击上月和下月切换月份
- 点击具体的日期可以在页面上显示选中日期
- 点击确定将会获得选中日期
- 点击灰色的日期可以跳转对应月份并高亮日期
结构
日历结构主要分为 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() // 2
new Date(2020, 5, 1).getDate() // 1
new 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'}) }, }
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。