最近做了一个小项目,但是需要使用日历,通过点击日历上的日期来获取数据,第一反应就是去问度娘,发现案例倒是很多,但是都打不到想要实现的效果,只能自己动手了。
下面先展示一下小样的初步形态:
然后就是码一下基本逻辑了,ui框架我是用的是weui,布局方式我使用了flex布局:
wxml :
←
{{canlender.thisDay}}
→
日
一
二
三
四
五
六
{{day.date}}
然后是wxss :
/* pages/cancelar/cancelar.wxss */
@import "../../lib/weui.wxss"; /* 这里需要引入weui.wxss样式规则 */
.placeholder{
margin: 5px;
padding: 0 10px;
text-align: center;
background-color: #EBEBEB;
height: 2.3em;
line-height: 2.3em;
color: #cfcfcf;
}
.flex-week {
background-color: #fff;
border-top : 2rpx solid#f00;
border-bottom : 2rpx solid#f00;
}
.flex-week .weui-flex__item view{
background-color: #fff;
color: #f00;
}
.flex-day .weui-flex__item .placeholder{
margin: 0rpx;
color: #fff;
background-color: #f00;
border : 1rpx solid#f00;
}
.day_late {
/* 可以点击的日期样式 */
background-color: #fff !important; border : 1rpx solid#EBEBEB !important; color: #cfcfcf !important;}.day_no { /* 无法操作的日期样式 */ background-color: #EBEBEB !important; border : 1rpx solid#fff !important; color: #cfcfcf !important;}.chooseDay { color: #000;}
然后就是展示js了,逻辑就不说了,直接贴代码:
Page({
data:{
canlender:{
'month': new Date().getMonth()+1,
'date': new Date().getDate(),
"day": new Date().getDay(),
'year': new Date().getFullYear(),
"weeks":[],
// 这是第几个索引
'thisIndex' : 0,
'thisDay' : '1980/01/01',
}
},
onLoad:function(options){
var _date = new Date()
var year = _date.getFullYear() //年
var month = _date.getMonth() + 1 //月
var date = _date.getDate() //日
this.showThisDay(_date,year,month,date);
},
/**
* 刷新页面值
*/
showThisDay : function(date,_year,_month,_date1){
// 页面初始化 options为页面跳转所带来的参数
var canlender = [], _date = new Date(date);
var year = _year, month = _month , date = _date1;
console.info(year + "-" + month + "-" + date)
var day = _date.getDay();
var firstDay = new Date(year, month - 1, 1).getDay();
var lastMonthDays = [];
// 上个月需要显示的天数
for (var i = firstDay - 1; i >= 0; i--) {
console.warn(new Date(year, month, -i).getDate())
lastMonthDays.push({
'year': year,
'date': new Date(year, month, -i).getDate() + '',
'month': month - 1,
'click': false,
'noDay': true,
})
}
var currentMonthDys = [];
// 这个月显示的天数进行判断 如果已经过去则没法点击
console.log('this date' + date);
for (var i = 1; i <= new Date(year, month, 0).getDate(); i++) {
if (i > date) {
currentMonthDys.push({
'year': year,
'date': i + "",
'month': month,
'click': true,
'noDay': false,
})
} else if (i == date) {
// 这里会打印的从1开始的
var fristDayLength = firstDay + i - 1;
this.setData({
'canlender.thisIndex': 0 + ',' + fristDayLength,
'canlender.thisDay': year+'/'+month+'/'+i
})
currentMonthDys.push({
'year': year,
'date': i + "",
'month': month,
'click': false,
'noDay': false,
})
} else {
currentMonthDys.push({
'year': year,
'date': i + "",
'month': month,
'click': false,
'noDay': true,
})
}
}
var nextMonthDays = []
var endDay = new Date(year, month, 0).getDay();
for (var i = 1; i < 7 - endDay; i++) {
nextMonthDays.push({
'year': year,
'date': i + '',
'month': parseInt(month) + 1,
'click': false,
'noDay': true,
})
}
canlender = canlender.concat(lastMonthDays, currentMonthDys, nextMonthDays)
var weeks = []
for (var i = 0; i < canlender.length; i++) {
if (i % 7 == 0) {
weeks[parseInt(i / 7)] = new Array(7);
}
weeks[parseInt(i / 7)][i % 7] = canlender[i]
}
console.info(weeks)
this.setData({
"canlender.weeks": weeks
})
},
/**
* 获取到当前天数
*/
getThisData : function(dom){
var xy = dom.currentTarget.dataset.index, thisDay = dom.currentTarget.dataset.date;
var xyArr = xy.split(',');
var x = parseInt(xyArr[0]) , y = parseInt(xyArr[1]);
if (xyArr[2] == true || xyArr[2] == 'true') return;
// index为从0开始的索引
var thisDayDomClick = "canlender.weeks[" + x + "][" + [y]+"].click";
var oldXy = this.data.canlender.thisIndex;
var oldXyArr = oldXy.split(',');
var oldx = parseInt(oldXyArr[0]), oldy = parseInt(oldXyArr[1]);
var oldDayDom = "canlender.weeks[" + oldx + "][" + oldy +"].click";
this.setData({
[oldDayDom]: true,
[thisDayDomClick] : false,
'canlender.thisIndex' : x+','+y,
'canlender.thisDay': thisDay,
})
},
/**
* bindDateChange
*/
bindDateChange : function(e){
var date = e.detail.value;
var dateArr = date.split('-');
var month = dateArr[1].substring(0, 1) == 0 || dateArr[1].substring(0, 1) == '0' ? dateArr[1].replace(/^[0-9]/, '') : dateArr[1];
var day = dateArr[2].substring(0, 1) == 0 || dateArr[2].substring(0, 1) == '0' ? dateArr[2].replace(/^[0-9]/, '') : dateArr[2];
var dateObj = new Date(dateArr[0]+'-'+month+'-'+day);
this.showThisDay(dateObj,dateArr[0],month,day);
},
onReady:function(){
// 页面渲染完成
},
onShow:function(){
// 页面显示
},
onHide:function(){
// 页面隐藏
},
onUnload:function(){
// 页面关闭
},
tap: function(e){
console.info(e)
}
})
到这里,就可以实现以下功能了(录屏的时候可能有阳光照射导致效果不是很好):
到这里,基本的日历框架逻辑就差不多了,然后把上面的代码写成组件然后集成到项目中就可以了:
组件的js :
// compent/cancelar.js
Component({
/**
* 组件的属性列表
*/
properties: {
title: { // 是否显示
type: Boolean,
value: true,
},
},
/**
* 组件的初始数据
*/
data: {
'month': new Date().getMonth() + 1,
'date': new Date().getDate(),
"day": new Date().getDay(),
'year': new Date().getFullYear(),
"weeks": [],
// 这是第几个索引
'thisIndex': 0,
'thisDay': '1980/01/01',
},
/**
* 组件的方法列表
*/
methods: {
// 内部方法
/**
* 刷新页面值
*/
showThisDay: function (date, _year, _month, _date1) {
// 页面初始化 options为页面跳转所带来的参数
var canlender = [], _date = new Date(date);
var year = _year, month = _month, date = _date1;
console.info(year + "-" + month + "-" + date)
var day = _date.getDay();
var firstDay = new Date(year, month - 1, 1).getDay();
var lastMonthDays = [];
// 上个月需要显示的天数
for (var i = firstDay - 1; i >= 0; i--) {
console.warn(new Date(year, month, -i).getDate())
lastMonthDays.push({
'year': year,
'date': new Date(year, month, -i).getDate() + '',
'month': month - 1,
'click': false,
'noDay': true,
})
}
var currentMonthDys = [];
// 这个月显示的天数进行判断 如果已经过去则没法点击
console.log('this date' + date);
for (var i = 1; i <= new Date(year, month, 0).getDate(); i++) {
if (i > date) {
currentMonthDys.push({
'year': year,
'date': i + "",
'month': month,
'click': true,
'noDay': false,
})
} else if (i == date) {
// 这里会打印的从1开始的
var fristDayLength = firstDay + i - 1;
this.setData({
'canlender.thisIndex': 0 + ',' + fristDayLength,
'canlender.thisDay': year + '/' + month + '/' + i
})
currentMonthDys.push({
'year': year,
'date': i + "",
'month': month,
'click': false,
'noDay': false,
})
} else {
currentMonthDys.push({
'year': year,
'date': i + "",
'month': month,
'click': false,
'noDay': true,
})
}
}
var nextMonthDays = []
var endDay = new Date(year, month, 0).getDay();
for (var i = 1; i < 7 - endDay; i++) {
nextMonthDays.push({
'year': year,
'date': i + '',
'month': parseInt(month) + 1,
'click': false,
'noDay': true,
})
}
canlender = canlender.concat(lastMonthDays, currentMonthDys, nextMonthDays)
var weeks = []
for (var i = 0; i < canlender.length; i++) {
if (i % 7 == 0) {
weeks[parseInt(i / 7)] = new Array(7);
}
weeks[parseInt(i / 7)][i % 7] = canlender[i]
}
console.info(weeks)
this.setData({
"canlender.weeks": weeks
})
},
/**
* 获取到当前天数
*/
getThisData: function (dom) {
var xy = dom.currentTarget.dataset.index, thisDay = dom.currentTarget.dataset.date;
var xyArr = xy.split(',');
console.log(xyArr[2]);
if (xyArr[2] == true) return;
var x = parseInt(xyArr[0]), y = parseInt(xyArr[1]);
// index为从0开始的索引
var thisDayDomClick = "canlender.weeks[" + x + "][" + [y] + "].click";
var oldXy = this.data.canlender.thisIndex;
var oldXyArr = oldXy.split(',');
var oldx = parseInt(oldXyArr[0]), oldy = parseInt(oldXyArr[1]);
var oldDayDom = "canlender.weeks[" + oldx + "][" + oldy + "].click";
this.setData({
[oldDayDom]: true,
[thisDayDomClick]: false,
'canlender.thisIndex': x + ',' + y,
'canlender.thisDay': thisDay,
})
},
/**
* picker 日历触发事件
*/
bindDateChange: function (e) {
var date = e.detail.value;
var dateArr = date.split('-');
var month = dateArr[1].substring(0, 1) == 0 || dateArr[1].substring(0, 1) == '0' ? dateArr[1].replace(/^[0-9]/, '') : dateArr[1];
var day = dateArr[2].substring(0, 1) == 0 || dateArr[2].substring(0, 1) == '0' ? dateArr[2].replace(/^[0-9]/, '') : dateArr[2];
var dateObj = new Date(dateArr[0] + '-' + month + '-' + day);
this.showThisDay(dateObj, dateArr[0], month, day);
// 用来显示前台的
var oldXy = this.data.canlender.thisIndex;
var oldXyArr = oldXy.split(',');
var oldx = parseInt(oldXyArr[0]), oldy = parseInt(oldXyArr[1]);
var oldDayDom = "canlender.weeks[" + oldx + "][" + oldy + "].click";
var thisDay = dateArr[0]+'/'+month+'/'+day;
this.setData({
'canlender.thisDay': thisDay,
});
// warn 这有个bug 就是无法控制原先的日期显示
// 发送点击组件的时间
this.triggerEvent("chooseEvent");
},
// 私有方法
_clickEvent: function (dom) {
var xy = dom.currentTarget.dataset.index, thisDay = dom.currentTarget.dataset.date;
var xyArr = xy.split(',');
if (xyArr[2] == true || xyArr[2] == 'true') return;
var x = parseInt(xyArr[0]), y = parseInt(xyArr[1]);
// index为从0开始的索引
var thisDayDomClick = "canlender.weeks[" + x + "][" + [y] + "].click";
var oldXy = this.data.canlender.thisIndex;
var oldXyArr = oldXy.split(',');
var oldx = parseInt(oldXyArr[0]), oldy = parseInt(oldXyArr[1]);
var oldDayDom = "canlender.weeks[" + oldx + "][" + oldy + "].click";
this.setData({
[oldDayDom]: true,
[thisDayDomClick]: false,
'canlender.thisIndex': x + ',' + y,
'canlender.thisDay': thisDay,
});
// 发送点击组件的时间
this.triggerEvent("chooseEvent");
}
}
})
到这里组件的功能基本就完成了,然后就是如何在页面中调用以及如何将数据传到当前页面中去了,组件与页面的数据交互我使用的是微信小程序的selectComponent方法,通过获取到组件对象直接获取和调用组建的方法,可以做一个小尝试:
在json中声明一下组件的名称:
在页面中引用一个组件:
在js中获取到这个组件:
然后打印组件中data对象里的数据就可以直接这么打印:
var getThisDay = this.dialog.data.canlender;
然后在想使用这个组件的页面直接引用该组件就可以了,但是组件在页面的样式我是在页面中定义的,因为项目中该组件的位置是不唯一的,我只把小样中的样式贴一下:
/* container模板样式 */
.container {
position: absolute;
top: 120px;
left: 0;
background-color: #fff;
width: 100%;
padding: 0px;
height: 330px;
}
到这里,如果全部集成进去的话样式基本就搞定了,之后就是按照你们的需要来制定了。