今天咱们一块儿写一个微信小程序日历组件css
微信小程序日历组件 github.com/749264345/w…html
好,咱们先看一下要实现的模样,以下图 git
1.日历能够经过按钮【切换展现效果】改变日历的呈现效果,上图是平铺模式,下图是收起滚动模式。 2.经过点击具体的日期能够在页面上显示当前选中的具体日期。 3.点击【今天】快速回到当日视图。 4.点击【◀】和【▶】切换月份。 上面的四点也是基本的交互需求,咱们立刻开始。 首先,咱们先结构后样式,作出最基本的界面结构 这边咱们把总体结构分红上中下,操做显示区,星期显示区,日期显示区。github
<view class='calendar'>
<!--显示当前年月日-->
<view class='calendar-title'>
<view class='item ctrl' bindtap='lastMonth'>{{lastMonth}}</view>
<view class='item title'>{{title}}</view>
<view class='item ctrl' bindtap='nextMonth'>{{nextMonth}}</view>
<view class='item ctrl today' bindtap='today'>今天</view>
</view>
<!--星期-->
<view class='calendar-week'>
<view class='item'>{{item}}</view>
</view>
<!--日期-->
<view class='calendar-container'>
<!--上个月占位格子-->
<view class='grid gray'>{{item}}</view>
<!--当月格子-->
<view class='grid'>
<view class="wrap">{{item.date}}</view>
</view>
<!--下个月占位格子-->
<view class='grid gray'>{{item}}</view>
</view>
</view>
复制代码
这是咱们基本的日历结构,机智的小伙伴已经从布局中知道咱们实现的大体逻辑了,是的,咱们先获取当月有多少天,上月和下月有多少天,这样咱们的日历就出来了。好,慢慢来,下面咱们详细说,咱们先写上基本的样式。算法
.calendar {
width: 100%;
text-align: center;
font-size: 30rpx;
box-sizing: border-box;
}
/* 标题 */
.calendar-title {
line-height: 70rpx;
font-size: 30rpx;
text-align: left;
padding: 0 20rpx;
box-sizing: border-box;
}
.calendar-title .ctrl {
display: inline-block;
padding: 0 20rpx;
background: #f5f5f5;
border-radius: 10rpx;
}
.calendar-title .item {
display: inline-block;
vertical-align: middle;
line-height: 50rpx;
}
.calendar-title .title {
min-width: 300rpx;
text-align: center;
}
.calendar-title .today {
float: right;
margin-top: 10rpx;
}
/* 星期 */
.calendar-week {
display: flex;
text-align: center;
padding: 20rpx 10rpx;
box-sizing: border-box;
border-top: 1rpx solid #e0e0e0;
border-bottom: 1rpx solid #e0e0e0;
background: #f5f5f5;
}
.calendar-week .item {
flex: 1;
}
/* 日期 */
.calendar-container {
display: flex;
flex-wrap: wrap;
padding: 20rpx 10rpx;
box-sizing: border-box;
}
.calendar-container .grid {
display: inline-block;
width: 14.28571428571429%;
line-height: 70rpx;
position: relative;
z-index: 1;
}
.calendar-container .grid.gray {
color: #ccc;
}
.calendar-container .grid .wrap.select {
background: rgb(49, 120, 228);
border-radius: 10rpx;
color: #fff;
width: 80%;
margin: 0 auto;
}
复制代码
以上咱们基本试下了日历的界面,下面咱们来实现星期和日期的展现。 好,咱们先显示星期,咱们先在组件中定义一个数组,用来遍历显示星期的标题;小程序
Component({
properties: {
//星期数组
weekText: {
type: Array,
value: ['周日', '周一', '周二', '周三', '周四', '周五', '周六']
}
},
...
})
复制代码
咱们将星期的标题定义为可配置的模式,默认显示如上的文字,以后咱们能够在组件外自定义,个性化显示。因而咱们调整下wxml的代码。微信小程序
<!--遍历星期-->
<view class='calendar-week'>
<view wx:for='{{weekText}}' class='item' wx:key='{{item}}'>{{item}}</view>
</view>
复制代码
这样咱们就能看到咱们想要的效果。 数组
new Date(year, month, date).getDate();微信
由此咱们作以下尝试 函数
因为JavaScript中day的范围为1~31中的值,因此当设为0时,会向前 一天,也即表示上个月的最后一天,经过这种方式能够获得每月份的天数。
知道了获取当月天数的原理,咱们还须要知道当月1号是星期几。 咱们使用以下的方法:
new Date(Date.UTC(year, month-1, date)).getDay();
// 组件的初始数据
data: {
//当月格子
thisMonthDays: [],
//上月格子
empytGridsBefore: [],
//下月格子
empytGridsAfter: [],
},
methods: {
//获取当月天数
getThisMonthDays: function (year, month) {
return new Date(year, month, 0).getDate();
},
// 绘制当月天数占的格子
createDays: function (year, month) {
let thisMonthDays = [],
days = this.getThisMonthDays(year, month);
for (let i = 1; i <= days; i++) {
thisMonthDays.push({
date: i,
dateFormat: this.zero(i),
monthFormat: this.zero(month),
week: this.data.weekText[new Date(Date.UTC(year, month - 1, i)).getDay()]
});
}
this.setData({
thisMonthDays
})
},
//获取当月空出的天数
createEmptyGrids: function (year, month) {
let week = new Date(Date.UTC(year, month - 1, 1)).getDay(),
empytGridsBefore = [],
empytGridsAfter = [],
emptyDays = (week == 0 ? 7 : week);
//当月天数
var thisMonthDays = this.getThisMonthDays(year, month);
//上月天数
var preMonthDays = month - 1 < 0
? this.getThisMonthDays(year - 1, 12)
: this.getThisMonthDays(year, month - 1);
//空出日期
for (let i = 1; i <= emptyDays; i++) {
empytGridsBefore.push(preMonthDays - (emptyDays - i));
}
var after = (42 - thisMonthDays - emptyDays) - 7 >= 0
? (42 - thisMonthDays - emptyDays) - 7
: (42 - thisMonthDays - emptyDays);
for (let i = 1; i <= after; i++) {
empytGridsAfter.push(i);
}
this.setData({
empytGridsAfter,
empytGridsBefore
})
},
//补全0
zero: function (i) {
return i >= 10 ? i : '0' + i;
},
}
复制代码
咱们一样修改下wxml代码,同时咱们为上月,下月,今天,三个按钮添加相关事件监听。
<!--显示当前年月日-->
<view class='calendar-title'>
<view class='item ctrl' bindtap='lastMonth'>{{lastMonth}}</view>
<view class='item title'>{{title}}</view>
<view class='item ctrl' bindtap='nextMonth'>{{nextMonth}}</view>
<view class='item ctrl today' bindtap='today'>今天</view>
</view>
复制代码
<!--上个月占位格子-->
<view class='grid gray' wx:for='{{empytGridsBefore}}' wx:key='{{item}}'>{{item}}</view>
<!--当月格子-->
<view class='grid' wx:for='{{thisMonthDays}}' wx:key='{{indx}}'>
<view class='self' wx:if="{{ format === year+'-'+item.monthFormat+'-'+item.dateFormat }}"></view>
<view class="wrap {{ select === year+'-'+item.monthFormat+'-'+item.dateFormat ? 'select' :''}}" bindtap='select' data-date='{{item.date}}'>{{item.date}}</view>
</view>
<!--下个月占位格子-->
<view class='grid gray' wx:for='{{empytGridsAfter}}' wx:key='{{item}}'>{{item}}</view>
复制代码
相关的事件监听:
//默认选中当天 并初始化组件
today: function () {
let DATE = this.data.defaultValue ? new Date(this.data.defaultValue) : new Date(),
year = DATE.getFullYear(),
month = DATE.getMonth() + 1,
date = DATE.getDate(),
select = year + '-' + this.zero(month) + '-' + this.zero(date);
this.setData({
format: select,
select: select,
year: year,
month: month,
date: date,
YEAR: year,
MONTH: month,
DATE: date,
})
//初始化日历组件UI
this.display(year, month, date);
//发送事件监听
this.triggerEvent('select', select);
},
//上个月
lastMonth: function () {
let month = this.data.month == 1 ? 12 : this.data.month - 1;
let year = this.data.month == 1 ? this.data.year - 1 : this.data.year;
//初始化日历组件UI
this.display(year, month, 0);
},
//下个月
nextMonth: function () {
let month = this.data.month == 12 ? 1 : this.data.month + 1;
let year = this.data.month == 12 ? this.data.year + 1 : this.data.year;
//初始化日历组件UI
this.display(year, month, 0);
},
复制代码
代码中咱们使用this.display(year, month, 0)为组件统一初始化; 同时在today函数中咱们添加事件监听函数,将选中的日期发送到页面,咱们经过事件订阅来获取的相关值。
<Calendar id="Calendar" bind:select="select"></Calendar>
复制代码
//组件监听事件
select(e) {
this.setData({
selectVal:e.detail
})
},
复制代码
最后咱们为切换显示效果的按钮添加事件:
toggleType(){
this.selectComponent('#Calendar').toggleType();
}
复制代码
组件中对应的方法,每当切换展现效果,组件都须要初始化
//切换展现
toggleType(){
this.setData({
toggleType: this.data.toggleType == 'mini' ? 'large' :'mini'
})
//初始化日历组件UI
this.display(this.data.year, this.data.month, this.data.date);
},
复制代码
以上基本上是小程序日历组件实现的基本逻辑,介于篇幅太长还有不少实现上的细节不在此一一细说,你们能够移步个人github
微信小程序日历组件 github.com/749264345/w…
上文中有不足之处,请给出建议或更优的实现方案,谢谢~ 最后祝你们五一快乐~~