一言不合就上图:
首先整合一些黑科技:
1.每个月的天数如何计算:new Date(year, month, 0).getDate()
解释说明:
7.Find a value t such that YearFromTime(t) == ym and MonthFromTime(t) == mn) and DateFromTime(t) == 1; but if this is not possible (because some argument is out of range), return NaN.
8.Return Day(t) + dt − 1.
上面这句话来自ES 规范:http://es5.github.io/#x15.9.1.12,这一节的第七和第八条,意思就是
简单解释下就是,传入 year, month, day 来获取一个新的日期实例时,会先获取指定年、月的 1 号,例如 year=2017, month=4,会先获取 2017-5-1 这个日期,这是上面第七步完成的。
然后第八步,上面这个日期会加上 day 参数的整数值,然后减去 1。
上面的话通俗一点讲就是:new Date(2018, 5, 0).getDate()这个获取的是2018年4月最后一天的日期
2.每个月第一天是周几的计算:new Date(year, month - 1, 1).getDay()
获取到当前月的总天数和1号对应的是星期几是不是瞬间感觉日历控件的逻辑也没有特别复杂了呢
具体实现步骤说明:
1.界面采用flex布局,当超过七个值时自动往下一行进行排列
2.实现日期前面的空白采用俩个for循环,第一个for循环循环空白值,第二个for循环循环日期值,空白值数组的长度等于当前月1号周几的长度
<view class="days box box-lr box-wrap">
<view wx:if="{{hasEmptyGrid}}" class="grid white-color box box-align-center box-pack-center" wx:for="{{empytGrids}}" wx:key="{{index}}" data-idx="{{index}}"></view>
<view class="grid white-color box box-align-center box-pack-center" wx:for="{{days}}" wx:key="{{index}}" data-idx="{{index}}">
<view bindtap='changeDate' data-index='{{index+1}}' class="day {{(index+1) ==today ? (curMonth==cur_month? 'border-radius pink-bg':'border-radius pink-bd') : ''}} box box-align-center box-pack-center">{{item}}</view>
</view>
</view>
3.选择日期的时候圆圈跟随变化,切换月份的时候变成无填充边框圆圈
<view class="day {{(index+1) ==today ? (curMonth==cur_month? 'border-radius pink-bg':'border-radius pink-bd') : ''}} box box-align-center box-pack-center">{{index+1}}</view>
使用步骤:
1.将date模板导入项目最外层
2.wxml页面添加
<import src="/date/date.wxml" />
<template is="date" data="{{weeks_ch,cur_year,cur_month,hasEmptyGrid,empytGrids,days,today,curMonth}}" />
3.wxss页面添加
@import "/date/date.wxss";
4.js页面添加
var date = require('../../date/date.js');
5.在onLoad初始化日期控件
onLoad: function (options) {
date.dateInit(this);
}
相关代码(后期会跟新到github上和码云上):
码云:https://gitee.com/mrxu314/xcx_gh
gitHub:https://github.com/mrxu0/xcx_gh
wxml:
<template name="date">
<view class="flex box box-tb box-align-center">
<view class="calendar pink-color box box-tb">
<view class="weeks box box-lr box-pack-center box-align-center">
<view class="flex week fs28" wx:for="{{weeks_ch}}" wx:key="{{index}}" data-idx="{{index}}">{{item}}</view>
</view>
<view class="top-handle fs28 box box-lr box-align-center box-pack-center">
<view class="prev box box-rl" bindtap="handleCalendar" data-handle="prev">
<view class="prev-handle box box-lr box-align-center box-pack-center">《</view>
</view>
<view class="date-area box box-lr box-align-center box-pack-center">{{cur_year || "--"}} 年 {{cur_month || "--"}} 月</view>
<view class="next box box-lr" bindtap="handleCalendar" data-handle="next">
<view class="next-handle box box-lr box-align-center box-pack-center">》</view>
</view>
</view>
<view class="days box box-lr box-wrap">
<view wx:if="{{hasEmptyGrid}}" class="grid white-color box box-align-center box-pack-center" wx:for="{{empytGrids}}" wx:key="{{index}}" data-idx="{{index}}">
</view>
<view class="grid white-color box box-align-center box-pack-center" wx:for="{{days}}" wx:key="{{index}}" data-idx="{{index}}">
<view bindtap='changeDate' data-index='{{index+1}}' class="day {{(index+1) ==today ? (curMonth==cur_month? 'border-radius pink-bg':'border-radius pink-bd') : ''}} box box-align-center box-pack-center">{{item}}</view>
</view>
</view>
</view>
</view>
</template>
wxss
.box {
display: flex;
}
.box-lr {
flex-direction: row;
}
.box-rl {
flex-direction: row-reverse;
}
.box-tb {
flex-direction: column;
}
.box-bt {
flex-direction: column-reverse;
}
.box-pack-center {
justify-content: center;
}
.box-pack-start {
justify-content: flex-start;
}
.box-pack-end {
justify-content: flex-end;
}
.box-pack-between {
justify-content: space-between;
}
.box-pack-around {
justify-content: space-around;
}
.box-align-center {
align-items: center;
}
.box-align-start {
align-items: flex-start;
}
.box-align-end {
align-items: flex-end;
}
.self-align-center {
align-self: center;
margin: 0 auto;
}
.self-align-start {
align-self: flex-start;
}
.self-align-end {
align-self: flex-end;
}
.self-align-stretch {
align-self: stretch;
}
.box-wrap {
flex-wrap: wrap;
}
.box-nowrap {
flex-wrap: nowrap;
}
.flex {
flex-grow: 1;
}
.shrink {
flex-shrink: 1;
}
.bg {
background-image: linear-gradient(to bottom, #faefe7, #ffcbd7);
overflow: hidden;
}
.brown-color {
color: #784344;
}
.pink-color {
color: #ff629a;
}
.white-color {
color: #fff;
}
.fs24 {
font-size: 24rpx;
}
.fs28 {
font-size: 28rpx;
}
.fs32 {
font-size: 32rpx;
}
.fs36 {
font-size: 36rpx;
}
.top-handle {
height: 80rpx;
}
.prev {
text-align: right;
height: 80rpx;
}
.next {
height: 80rpx;
}
.prev-handle {
width: 80rpx;
height: 100%;
}
.next-handle {
width: 80rpx;
height: 100%;
}
.date-area {
width: 50%;
height: 80rpx;
text-align: center;
}
.weeks {
height: 50rpx;
line-height: 50rpx;
opacity: 0.5;
}
.week {
text-align: center;
}
.days {
height: 500rpx;
}
.grid {
width: 107.1428571429rpx;
}
.day {
width: 60rpx;
height: 60rpx;
color: #88d2ac;
font-size: 26rpx;
font-weight: 200;
}
.border-radius {
border-radius: 50%;
position: relative;
left: 0;
top: 0;
}
.pink-bg {
background-color: #ff629a;
color: #fff;
}
.pink-bd {
border: 1px solid #ff629a;
}
.purple-bg {
background-color: #b8b8f1;
}
.right-triangle::after {
content: "";
display: block;
width: 0;
height: 0;
border: 15rpx solid transparent;
border-left-color: #ff629a;
position: absolute;
right: -22rpx;
top: 18rpx;
}
.left-triangle::before {
content: "";
display: block;
width: 0;
height: 0;
border: 15rpx solid transparent;
border-right-color: #ff629a;
position: absolute;
left: -22rpx;
top: 18rpx;
}
.tips {
text-align: center;
margin-top: 20rpx;
margin-bottom: 20rpx;
}
.types {
background-color: #ffedf4;
height: 50rpx;
}
.type-dot {
width: 25rpx;
height: 25rpx;
border-radius: 50%;
margin-right: 10rpx;
}
.type-dot-ymq {
color: rgb(255, 124, 160);
background-color: rgb(255, 124, 160);
}
.type-dot-ycq {
color: rgb(255, 200, 202);
background-color: rgb(255, 200, 202);
}
.type-dot-aqq {
color: rgb(118, 191, 92);
background-color: rgb(118, 191, 92);
}
.type-dot-yyq {
color: rgb(255, 182, 236);
background-color: rgb(255, 182, 236);
}
.type-dot-plr {
color: rgb(211, 189, 215);
background-color: rgb(211, 189, 215);
}
.types-desc {
padding: 0 20rpx;
}
.type-name {
margin-top: 50rpx;
margin-bottom: 30rpx;
}
.type-desc {
padding: 0 35rpx;
line-height: 38rpx;
}
.explain {
border-top: 1px solid #eee;
width: 90%;
margin: 20rpx 5% 20rpx 5%;
padding: 20rpx 0;
}
.explain-title {
font-weight: bold;
margin-bottom: 15rpx;
}
.explain-item {
padding: 8rpx 20rpx;
color: #fff;
}
.left-border-radius {
border-top-left-radius: 20rpx;
border-bottom-left-radius: 20rpx;
}
.right-border-radius {
border-top-right-radius: 20rpx;
border-bottom-right-radius: 20rpx;
}
js
var that;
/**
* 初始化数据
*/
function init(target) {
that = target;
const date = new Date();
const cur_year = date.getFullYear();
const cur_month = date.getMonth() + 1;
const weeks_ch = ['日', '一', '二', '三', '四', '五', '六'];
//空的网格计算
calculateEmptyGrids(cur_year, cur_month);
//计算日子
calculateDays(cur_year, cur_month);
that.setData({
cur_year,
cur_month,
weeks_ch,
today: new Date().getDate(),
curMonth: new Date().getMonth() + 1,
hasEmptyGrid:false
})
that.setData({
target_date: that.data.cur_year + '-' + that.data.curMonth + '-' + that.data.today
})
that.changeDate = changeDate;
that.handleCalendar = handleCalendar;
}
/**
* 空的网格计算
*/
function calculateEmptyGrids(year, month) {
const firstDayOfWeek = getFirstDayOfWeek(year, month);
let empytGrids = [];
if (firstDayOfWeek > 0) {
for (let i = 0; i < firstDayOfWeek; i++) {
empytGrids.push(i);
}
that.setData({
hasEmptyGrid: true,
empytGrids
});
} else {
that.setData({
hasEmptyGrid: false,
empytGrids: []
});
}
}
/**
* 获取这个月有几天
*/
function getThisMonthDays(year, month) {
console.log("获取这个月有几天", new Date(year, month, 0).getDate());
return new Date(year, month, 0).getDate();
}
/**
* 改变当前选中的值
*/
function changeDate(e) {
that.setData({
today: e.currentTarget.dataset.index,
curMonth:that.data.cur_month
});
that.setData({
target_date: that.data.cur_year + '-' + that.data.curMonth + '-' + that.data.today
})
console.log("返回选中的值",that.data.target_date);
};
/**
* 获取第一个周的周几
*/
function getFirstDayOfWeek(year, month) {
console.log("获取第一个周的周几", new Date(Date.UTC(year, month - 1, 1)).getDay(), Date.UTC(year, month - 1, 1), new Date(year, month - 1, 1).getDay());
return new Date(Date.UTC(year, month - 1, 1)).getDay();
}
/**
* 生成对应本月数据的数组
*/
function calculateDays(year, month) {
let days = [];
const thisMonthDays = getThisMonthDays(year, month);
for (let i = 1; i <= thisMonthDays; i++) {
days.push(i);
}
that.setData({
days
});
}
/**
* 查看前一个月还是后一个月
*/
function handleCalendar(e) {
const handle = e.currentTarget.dataset.handle;
const cur_year = that.data.cur_year;
const cur_month = that.data.cur_month;
if (handle === 'prev') {
let newMonth = cur_month - 1;
let newYear = cur_year;
if (newMonth < 1) {
newYear = cur_year - 1;
newMonth = 12;
}
calculateDays(newYear, newMonth);
calculateEmptyGrids(newYear, newMonth);
that.setData({
cur_year: newYear,
cur_month: newMonth
})
} else {
let newMonth = cur_month + 1;
let newYear = cur_year;
if (newMonth > 12) {
newYear = cur_year + 1;
newMonth = 1;
}
calculateDays(newYear, newMonth);
calculateEmptyGrids(newYear, newMonth);
that.setData({
cur_year: newYear,
cur_month: newMonth
})
}
}
module.exports = {
dateInit:init
}
日期控件这种需求还是比较常见的,博主在这里实现的是选择指定日期返回值得方式。下次碰到连续选择日期的需求,博主也会整合进来。将会对这个日期控件持续进行扩展,要是评论数超过二十条楼主也会考虑实现这个功能的
参考链接:
https://segmentfault.com/q/1010000011402629?sort=created
初始日历控件是朋友给的,不知道地址。忘作者见谅
喜欢我可以关注我的公众号,更多精彩内容可以早一步观看