描述
切换月份, 当天文案为今天, 日期背景变色, 日期红点标识, 点击选中日期.
效果
源码
calendar.wxml
<view class="component">
<view class="header">
<view bindtap="handlePrevMonthClick">{{\'<\'}}</view>
<view>{{year}}年{{month}}月</view>
<view bindtap="handleNextMonthClick">></view>
</view>
<view>
<view class="week">周一</view>
<view class="week">周二</view>
<view class="week">周三</view>
<view class="week">周四</view>
<view class="week">周五</view>
<view class="week">周六</view>
<view class="week">周日</view>
</view>
<view class="daybox">
<block wx:for="{{dayList}}" wx:key="{{index}}">
<view wx:if="{{item.day}}" class="day {{item.day === day ? \'day-checked\': \'\'}} {{item.bg ? \'day-bg\' : \'\'}}" data-day="{{item.day}}" bindtap="handleDayClick">
<view>{{item.isToday ? \'今天\' : item.day}}</view>
<view class="point" wx:if="{{item.point}}"></view>
</view>
<view wx:else class="day"></view>
</block>
</view>
</view>
calendar.js
const weekNameMap = [\'周日\', \'周一\', \'周二\', \'周三\', \'周四\', \'周五\', \'周六\'];
Component({
properties: {
mydate: String, // 选中的天 Date String 格式
mylist: Array,
},
data: {
year: null,
month: null,
day: null,
list: [],
},
lifetimes: {
attached: function () {
const now = new Date();
this.setData({
year: now.getFullYear(),
month: now.getMonth() + 1,
day: now.getDate(),
}, this.calcDayList)
},
},
observers: {
\'mydate\': function (mydate) {
let date = new Date(mydate);
this.setData({
year: date.getFullYear(),
month: date.getMonth() + 1,
day: date.getDate(),
}, this.calcDayList);
},
\'mylist\': function (mylist) {
this.setData({ list: mylist }, this.calcDayList);
},
},
methods: {
// 获取当月共多少天
getThisMonthDays: function (year, month) {
return new Date(year, month, 0).getDate()
},
// 获取当月第一天星期几 0 星期日
getFirstDayOfWeek: function (year, month) {
return new Date(Date.UTC(year, month - 1, 1)).getDay();
},
calcDayList: function () {
const { year, month, list, } = this.data;
let totalDay = this.getThisMonthDays(year, month);
let firstDay = this.getFirstDayOfWeek(year, month);
let dayList = [];
for (let i = 0; i < (totalDay); i++) {
dayList.push({
day: i + 1,
weekName: weekNameMap[(firstDay + i) % 7],
})
}
// 向前添加
for (let i = 0; i < (firstDay || 7) - 1; i++) {
dayList.unshift({ day: 0, });
}
// 向后添加
for (let i = 0; i < 42 - totalDay - ((firstDay || 7) - 1); i++) {
dayList.push({ day: 0, });
}
// 当天
let now = new Date();
if (now.getFullYear() === year && now.getMonth() + 1 === month) {
(dayList.find(d => d.day === now.getDate()) || {}).isToday = true;
}
// 业务数据处理
list.forEach(item => {
let find = dayList.find(d => d.day === item.day);
if (find) {
Object.assign(find, item);
}
})
this.setData({ dayList, });
},
// 点击上个月
handlePrevMonthClick: function () {
let year = this.data.year;
let month = this.data.month;
if (this.data.month === 1) {
year = this.data.year - 1;
month = 12;
} else {
month = this.data.month - 1;
}
this.handleDateChange({ year, month });
},
// 点击下个月
handleNextMonthClick: function () {
let year = this.data.year;
let month = this.data.month;
if (this.data.month === 12) {
year = this.data.year + 1;
month = 1;
} else {
month = this.data.month + 1;
}
this.handleDateChange({ year, month });
},
// 点击 天
handleDayClick: function (e) {
const { day } = e.currentTarget.dataset;
this.handleDateChange({ day })
},
// 处理日期变化
handleDateChange: function (time) {
const { year, month, day } = this.data;
let date = { year, month, day, ...time };
if (!this.data.mydate) {
this.setData({ ...date });
if (time.year || time.month) this.calcDayList();
}
this.triggerEvent(\'mydatechange\', { date: new Date(`${date.year}/${date.month}/${date.day}`).toString() })
}
}
})
calendar.wxss
.component {
background: #fff;
}
.header {
display: flex;
justify-content: space-around;
padding: 20rpx;
border-top: 1px solid #eee;
}
.header view {
height: 80rpx;
line-height: 80rpx;
font-size: 40rpx;
color: rgba(0, 0, 0, 0.85);
min-width: 100rpx;
}
.header view:nth-child(2n-1) {
font-size: 50rpx;
}
.week {
display: inline-block;
width: 107rpx;
line-height: 2;
color: rgba(0, 0, 0, 0.45);
font-size: 28rpx;
text-align: center;
}
.daybox {
display: flex;
flex-wrap: wrap;
border-bottom: 1px solid #eee;
}
.day {
width: 107rpx;
height: 107rpx;
box-sizing: border-box;
text-align: center;
line-height: 2;
color: rgba(0, 0, 0, 0.85);
border: 4rpx solid #fff;
}
.day:nth-child(7n), .day:nth-child(7n-1) {
color: #ff9b80;
}
.day-checked {
border: 4rpx solid #ffa78f!important;
border-radius: 10rpx;
}
.day-bg {
background: #ffe9e4!important;
}
.point {
width: 10rpx;
height: 10rpx;
border-radius: 50%;
background: #ff876d;
margin: 0 auto;
margin-top: 5rpx;
}
calendar.json
{
"component": true,
"usingComponents": {}
}
使用例子
参数 | 类型 | 默认值 | 说明 |
---|---|---|---|
mydate? | String | 当天时间字符串 | 选中的日期 |
mylist? | Array | [] | 当月数据 |
handleDateClick? | ({ detail: { date } }) => void | 点击某天的的回调 |
test.wxml
<calendar mydate="{{mydate}}" mylist="{{list}}" bindmydatechange="handleDateClick" />
test.js
Page({
data: {
mydate: new Date().toString(),
mylist: [
{ day: 1, // 当月天
bg: true, // 是否显示背景
point: true, // 是否显示圆点
},
{ day: 3, bg: true },
{ day: 4, bg: true },
{ day: 5, bg: true, point: true },
{ day: 6, bg: true, point: true },
{ day: 7, point: true },
{ day: 8, point: true },
{ day: 9, point: true },
]
},
handleDateClick: function ({ detail: { date } }) {
this.setData({ mydate: date });
},
})
test.json
{
"navigationBarTitleText": "demo",
"usingComponents": {
"calendar": "/components/calendar/calendar"
}
}
注意
组件properties的数据类型不支持Date, 所以日期使用字符串格式传递。