前些日子闲聊群里有人提了用js画全年日历的需求,趁闲暇时间画了个小demo,下面还是先上效果图吧。
高亮显示的是今天的日期和标记要高亮显示的日期,也添加了点击事件的钩子,自己可以实现钩子函数,从而操作点击的日期值。
下面还是先上dai
/**
* 日历视图
*/
class DateView{
/**
* [constructor 构造]
* @param {[type]} option [description]
* @return {[type]} [description]
*/
constructor(option){
this.FtColor=option?.FtColor==undefined?"#000":option?.FtColor;
this.BdColor=option?.BdColor==undefined?"#fff":option?.BdColor;
this.BgColor=option?.BgColor==undefined?"#fff":option?.BgColor;
this.FtSize=option?.FtSize==undefined?"30px":option?.FtSize;
this.padding=option?.padding==undefined?"10px":option?.padding;
this.parent=option?.parent==undefined?"body":option?.parent;
this.index=0;
}
/**
* [setFtColor 设置字体颜色]
* @param {[type]} FtColor [description]
*/
setFtColor(FtColor){
this.FtColor=FtColor;
return this;
}
/**
* [setBdColor 设置边框颜色]
* @param {[type]} BdColor [description]
*/
setBdColor(BdColor){
this.BdColor=BdColor;
return this;
}
/**
* [setBgColor 设置背景颜色]
* @param {[type]} BgColor [description]
*/
setBgColor(BgColor){
this.BgColor=BgColor;
return this;
}
/**
* [setFtSize 设置字体大小]
* @param {[type]} FtSize [description]
*/
setFtSize(FtSize){
this.FtSize=FtSize;
return this;
}
/**
* [setPadding 设置padding]
* @param {[type]} padding [description]
*/
setPadding(padding){
this.padding=padding;
return this;
}
/**
* [setParent 设置日历容器]
* @param {[type]} parent [description]
*/
setParent(parent){
this.parent=parent;
return this;
}
/**
* [drawDateByMonth 取得某一月的日历视图]
* @param {[type]} yearOrmonth [年或月]
* @param {[type]} Month [月]
* @param {[type]} callBack [钩子函数,点击日期后的动作]
* @param {[type]} width [控件宽度]
* @param {[type]} tagData [需要高亮显示的日期数据如['2023.1.12','2023.1.13']]
* @return {[type]} [description]
*/
drawDateByMonth(yearOrmonth,Month,callBack,width,tagData){
let date=new Date();
let year,month;
if(yearOrmonth==undefined){
year=date.getFullYear();
month=date.getMonth()+1;
}else if(yearOrmonth!=undefined&&yearOrmonth>12){
year=yearOrmonth;
if(Month==undefined){
throw new Error("缺少参数“月份”");
}
month=Month;
}else{
year=date.getFullYear();
month=yearOrmonth;
}
if(year<1900||year>2100){
throw new Error("年份超出了限定区间1900-2100");
}
let html=`<style>
.dateView${this.index}{
position: relative;
${width};
margin-left:10px;
color:${this.FtColor};
font-size: ${this.FtSize};
background: ${this.BdColor};
display:inline-block;
vertical-align:top;
padding:10px;
}
.dateView${this.index} tr{
background: ${this.BdColor};
}
.dateView${this.index} tr td{
background: ${this.BgColor};
padding: ${this.padding};
cursor:pointer;
}
.dateView${this.index}Tag{
color:${this.BgColor};
background: ${this.FtColor} !important;
}
</style>
<table class="dateView${this.index}">
<tr>
<td colspan="7">${month}月</td>
</tr>
<tr>
<td>一</td><td>二</td><td>三</td><td>四</td><td>五</td><td>六</td><td>七</td>
</tr>`;
let days=this.getDaysByYearAndMonth(year,month);//本月多少天
let firstDay=new Date(year+"/"+month+"/1 1:1:1").getDay();//本月第一天是星期几
firstDay=firstDay==0?6:firstDay-1;
let weeks=Math.ceil((days+firstDay)/7);//本月有几周
let dateArr=[];
for(var i=1;i<weeks*7+1;i++){
if((i-firstDay<=0)||(i-firstDay>days)){
dateArr.push("");
}else{
dateArr.push(i-firstDay);
}
}
function splitArray(array, size){
let data = [];
for (let i = 0; i < array.length; i += size) {
data.push(array.slice(i, i + size))
}
return data
}
dateArr=splitArray(dateArr,7);
tagData=tagData==undefined?[]:tagData;
let today=new Date();
today=today.getFullYear()+"-"+(today.getMonth()+1)+"-"+today.getDate();
tagData.push(today);
for(var i in dateArr){
html+=`<tr>`;
for(var j in dateArr[i]){
var t=`${year}-${month}-${dateArr[i][j]}`;
if(tagData.indexOf(t)>=0){
html+=`<td class="dateView${this.index}Tag" t="${t}">${dateArr[i][j]}</td>`;
}else{
html+=`<td t="${t}">${dateArr[i][j]}</td>`;
}
}
html+=`</tr>`;
}
if(this.parent=="body"){
document.body.insertAdjacentHTML("beforeend",html);
}else{
document.querySelector(this.parent).insertAdjacentHTML("beforeend",html);
}
if(callBack!=undefined){
document.querySelector(`.dateView${this.index}`).addEventListener('click',function(e){
if(e.target.getAttribute("t")!=null){
callBack(e.target.getAttribute("t"));
}
});
}
this.index++;
}
/**
* [getDaysByYearAndMonth 根据年月取得月份的天数]
* @param {[type]} year [年]
* @param {[type]} month [月]
* @return {[type]} [description]
*/
getDaysByYearAndMonth(year,month){
if([1,3,5,7,8,10,12].indexOf(month)>=0){
return 31;
}else if(month==2){
if(year%100==0){
if(year%400==0){
return 29;
}else{
return 28;
}
}else{
if(year%4==0){
return 29;
}else{
return 28;
}
}
}else{
return 30;
}
}
/**
* [drawDateByYear 画出某一年全年的日历]
* @param {[type]} year [年]
* @param {[type]} cols [一行显示几个月份]
* @param {[type]} callBack [钩子函数,点击日期后的动作]
* @param {[type]} tagData [需要高亮显示的日期数据如['2023.1.12','2023.1.13']]
* @return {[type]} [description]
*/
drawDateByYear(year,cols,callBack,tagData){
year=year==undefined?new Date().getFullYear():year;
cols=cols==undefined?5:cols;
let width="width:"+Math.floor(100/cols-1)+"%";
console.log(width)
for(var i=1;i<=12;i++){
this.drawDateByMonth(year,i,callBack,width,tagData);
}
}
}
let d=new DateView({
FtSize:"20px",
FtColor:"#123ae3"
});
d.drawDateByYear(2023,5,function(v){
alert(v);
},[
'2023-10-13',
'2023-9-26',
'2023-10-12'
]);
使用也很简单,本文开始的效果图,实现代码如下
let d=new DateView({
FtSize:"20px",
FtColor:"#123ae3"
});
d.drawDateByYear(2023,5,function(v){
alert(v);
},[
'2023-10-13',
'2023-9-26',
'2023-10-12'
]);
其中FtSize为字体大小,Ftcolor为字体颜色,具体设置看构造函数,也有单独的设置字体大小颜色等配置的函数,通过链式操作即可,例如
let d=new DateView({
FtSize:"20px",
FtColor:"#123ae3"
});
也可以写成
let d=new DateView();
d.setFtColor("#123ae3").FtSize("20px");
或者也可以不传入任何参数,将默认输出黑白日历
drawDateByYear()方法画出全年的日历,也可以用drawDateByMonth()方法画出某个月的单月日历,默认将日历dom插入到body里,也可以通过传入parent修改日历容器,例如某个div,d.drawDateByYear(2023,5,function(v){
alert(v);
},[
'2023-10-13',
'2023-9-26',
'2023-10-12'
]);
其中这个匿名函数
function(v){
alert(v);
}为点击回调的钩子函数,这个是点击相应日期后alert()以下被点击的日期,这个自己根据业务需要实现。
后面这个数组就是要高亮显示的日期
代码都有注释,比较明了了