下拉月历状态 上拉周历状态因为最近项目很多地方用日历,所以就写了一个,可以来回切月历和周历,效果图就是下面这两张
html部分
<div class="calender-box">
<div class="calender-header">
<span id="pre">上一月</span>
<div class="date-box">
<i id="year"></i>
<i id="month"></i>
<i id="date" style="display: none;"></i>
</div>
<span id="next">下一月</span>
</div>
<!-- 周 -->
<div class="week-box">
<ul>
<li>星期日</li>
<li>星期一</li>
<li>星期二</li>
<li>星期三</li>
<li>星期四</li>
<li>星期五</li>
<li>星期六</li>
</ul>
</div>
<!-- 日历 -->
<div class="calender-content">
<ul id="calender">
<!-- <li><span class="opa">31</span></li>
<li><span>1</span></li> -->
</ul>
</div>
</div>
css部分
ul,li{
padding:0;
margin:0;
list-style:none;
}
.calender-box{
width:1000px;
margin:0 auto;
margin-top:50px;
}
.calender-header{
display:flex;
justify-content:center;
}
.calender-header span{
cursor:pointer;
color:#14C48B;
}
.calender-header i{
font-style:normal;
}
.date-box{
margin:0 20px;
}
.week-box{
margin-top:20px;
}
.week-box li{
width:50px;
}
.week-box ul,.calender-content ul{
display:flex;
justify-content:center;
flex-wrap:wrap;
width:480px;
margin:0 auto;
}
.calender-content ul{
justify-content:flex-start;
min-height:32px;
max-height:192px;
margin-top:20px;
overflow:hidden;
user-select:none;
-webkit-user-select:none;
-moz-user-select:none;
-ms-user-select:none; user-select:none;
}
.week-box li:first-child ~ li{
margin-left:20px;;
}
.calender-content li{
width:50px;
text-align:center;
line-height:32px;
margin-left:20px;
cursor:pointer;
}
.calender-content li:nth-child(7n+1){
margin-left:0px;
}
.active{
background:aqua;
}
.sign{
background:aquamarine;
}
.opa{
color:#ccc;
}
js部分
//获取需要显示日历UI的元素
let calenderDom=document.querySelector("#calender");
//获取点击上一月下一月的元素
let preDom=document.querySelector("#pre");
let nextDom=document.querySelector("#next");
//获取显示年月日的元素
let yearDom=document.querySelector("#year");
let monthDom=document.querySelector("#month");
let dateDom=document.querySelector("#date");
// 因为要显示上个月的和下个月的个别天数,并且每行7天,所以需要6行才能显示全,也就是42个天数
//是否是周模式,默认是月历模式
let isWeek=false;
//如果是周模式,选中的是月历哪一行
let lineNum=0;
//获取当前年当前月的1号是星期几
function getWeekDay(year,month){
let date=new Date(year,month,1);
return date.getDay();
}
//获取显示当前月 天数
/*
year是年
month是月
flag如果是true 是当前月,false表示上个月或者下个月,来区别显示DOM UI上的颜色
*/
function getMonthCount(year,month,flag=true){
let firstDate=new Date(year,month,1);//当月第一天
let lastDate=new Date(year,month+1,0);//当月最后一天
let countDate=lastDate.getDate()-firstDate.getDate()+1;
return Array.from(new Array(countDate),(item,value)=>{
return {
year,
month,
flag,
num:value+1
}
});
}
//每个月的几号在月历第几行
function getCalenderLine(year,month,date){
let preCountNum=getPreMonthCount(year,month);//获取上个月的天数
let weekDay=getWeekDay(year,month);//当前月的1号星期几
let preCount=Array.from(new Array(preCountNum.length),(item,value)=>value+1);//上个月的天数数组
let preArr=preCount.slice(-weekDay);//上个月取的天数正好是当前月1号星期几前面的天数
//每个月的几号在第几行
return parseInt((parseInt(date-1)+preArr.length)/7)+1;
}
//获取下个月 天数
function getNextMonthCount(year,month){
if(month===11){
return getMonthCount(year+1,0,false);
}else{
return getMonthCount(year,month+1,false);
}
}
//获取上个月 天数
function getPreMonthCount(year,month){
if(month===0){
return getMonthCount(year-1,11,false);
}else{
return getMonthCount(year,month-1,false);
}
}
//初始化当前月历今天日期
let initDate=new Date();
let initYear=initDate.getFullYear();
let initMonth=initDate.getMonth();
let initNum=initDate.getDate();
//点击后日历的年 月 日,默认是初始化的日期
let activeYear=initYear;
let activeMonth=initMonth;
let activeNum=initNum;
//日历更新后的年月日
let currentYear=initYear;
let currentMonth=initMonth;
let currentNum=initNum;
//渲染当前日
dateDom.innerHTML=zeroize(initNum,2)+'日';
//初始化日历
renderCalender(initYear,initMonth);
//初始化打开后当天日期是在日历的第几行
//lineNum=getCalenderLine(initYear,initMonth,initNum);
//渲染月历的方法
function renderCalender(year,month){
//初始化当前月历天数
let initCount=getMonthCount(year,month);
//初始化上个月的月历天数
let preCount=getPreMonthCount(year,month);
//初始化下个月的月历天数
let nextCount=getNextMonthCount(year,month);
//当前月的1号星期几
let weekDay=getWeekDay(year,month);
//合并要显示的月历天数
let resArr=[];//合并天数的数组
//上个月需要的天数
let preArr=[];
if(weekDay==0){//如果是0,表示是星期日,就是最开头,所以是不需要上个月的天数的
}else{
preArr=preCount.slice(-weekDay);//上个月取的天数正好是当前月1号星期几前面的天数
}
//下个月需要的天数 42减去当前月的天数和上个月的天数
let nextArr=nextCount.slice(0,42-initCount.length-preArr.length);
//所有需要显示的天数
resArr=[].concat(preArr,initCount,nextArr);
//将所需要的天数渲染到dom中
let str="";
resArr.forEach((item)=>{
//渲染当年当月当天的颜色
if(initYear==item.year&&initMonth==item.month&&initNum==item.num){
str+=`<li class="active" data-year="${item.year}" data-month="${item.month}" data-num="${item.num}"><span>${zeroize(item.num,2)}</span></li>`;
}else if(activeYear==item.year&&activeMonth==item.month&&activeNum==item.num){//记录点击后的日历
str+=`<li class="sign" data-year="${item.year}" data-month="${item.month}" data-num="${item.num}"><span>${zeroize(item.num,2)}</span></li>`;
}else if(item.flag){//是当前月,UI颜色正常
str+=`<li data-year="${item.year}" data-month="${item.month}" data-num="${item.num}"><span>${zeroize(item.num,2)}</span></li>`;
}else{//是上个月或者下个月,UI颜色灰色
str+=`<li data-year="${item.year}" data-month="${item.month}" data-num="${item.num}"><span class="opa">${zeroize(item.num,2)}</span></li>`;
}
});
//渲染日历dom
calenderDom.innerHTML=str;
//给日历日期添加添加点击事件
let liArr=document.querySelectorAll("#calender li");
liArr.forEach(item=>{
item.addEventListener("click",()=>{
liArr.forEach(item=>{//清楚标记class
item.classList.remove("sign");
});
item.classList.add("sign");
//可以处理函数,比如去请求接口 dataset里是标签上的属性有year month num
callbackCalender(item.dataset);
});
});
//渲染年月日
yearDom.innerHTML=year+'年';
monthDom.innerHTML=zeroize(month+1,2)+'月';
}
//渲染周历的方法
/*
flag:如果是从月历状态切换成周历状态就是false,是在周历状态下操作的是true
*/
function renderWeekCaleder(flag){
let tDate=null;
if(currentYear!=activeYear || currentMonth!=activeMonth){//如果点击日历的月份和显式的月份不一致,就用显示的月份的1号
tDate=flag ? new Date(currentYear,currentMonth,currentNum) : new Date(currentYear,currentMonth,1);
}else if(currentYear==activeYear || currentMonth==activeMonth){
tDate=flag ? new Date(currentYear,currentMonth,currentNum) : new Date(currentYear,currentMonth,activeNum);
}
//算出当前周的第一天是那一天,当前日期减去当前日期星期几就是本周的第一天的日期
let firstDate=currentNum-tDate.getDay();
if(currentYear!=activeYear || currentMonth!=activeMonth){//如果点击日历的月份和显式的月份不一致,就用显示的月份的1号
firstDate=flag ? currentNum-tDate.getDay() : 1-tDate.getDay();
}else if(currentYear==activeYear || currentMonth==activeMonth){
firstDate=flag ? currentNum-tDate.getDay() : activeNum-tDate.getDay();
}
//循环渲染出本周七天的日期
let str="";
for(let i=firstDate;i<(firstDate+7);i++){
let oDate=new Date(currentYear,currentMonth,i);
let wYear=oDate.getFullYear();
let wMonth=oDate.getMonth();
let wDate=oDate.getDate();
let flag=true;
if(wMonth!=currentMonth){//如果点击的日期的月份和循环的日期的月份不一样
flag=false
}
if(initYear==wYear&&initMonth==wMonth&&initNum==wDate){//渲染当年当月当天的颜色
str+=`<li class="active" data-year="${wYear}" data-month="${wMonth}" data-num="${wDate,2}"><span>${zeroize(wDate,2)}</span></li>`;
}else if(activeYear==wYear&&activeMonth==wMonth&&activeNum==wDate){//记录点击后的日历
str+=`<li class="sign" data-year="${wYear}" data-month="${wMonth}" data-num="${wDate,2}"><span>${zeroize(wDate,2)}</span></li>`;
}else if(flag){//是当前月,UI颜色正常
str+=`<li data-year="${wYear}" data-month="${wMonth}" data-num="${wDate}"><span>${zeroize(wDate,2)}</span></li>`;
}else{//是上个月或者下个月,UI颜色灰色
str+=`<li data-year="${wYear}" data-month="${wMonth}" data-num="${wDate}"><span class="opa">${zeroize(wDate,2)}</span></li>`;
}
}
//渲染日历dom
calenderDom.innerHTML=str;
//给日历日期添加添加点击事件
let liArr=document.querySelectorAll("#calender li");
liArr.forEach(item=>{
item.addEventListener("click",()=>{
liArr.forEach(item=>{//清楚标记class
item.classList.remove("sign");
});
item.classList.add("sign");
//可以处理函数,比如去请求接口 dataset里是标签上的属性有year month num
callbackCalender(item.dataset);
});
});
//渲染年月日
yearDom.innerHTML=currentYear+'年';
monthDom.innerHTML=zeroize(currentMonth+1,2)+'月';
}
//点击上一月或者上一周
preDom.addEventListener("click",()=>{
if(isWeek){//如果是周日历
let date=new Date(currentYear,currentMonth,parseInt(currentNum)-7);
currentYear=date.getFullYear();
currentMonth=date.getMonth();
currentNum=date.getDate();
renderWeekCaleder(true);
}else{//是月历
if(currentMonth==0){
currentMonth=11;
currentYear-=1;
renderCalender(currentYear,currentMonth);
}else{
currentMonth-=1;
renderCalender(currentYear,currentMonth);
}
}
});
//点击下一月或者下一周
nextDom.addEventListener("click",()=>{
if(isWeek){//如果是周日历
let date=new Date(currentYear,currentMonth,parseInt(currentNum)+7);
currentYear=date.getFullYear();
currentMonth=date.getMonth();
currentNum=date.getDate();
renderWeekCaleder(true);
}else{//是月历
if(currentMonth==11){
currentMonth=0;
currentYear+=1;
renderCalender(currentYear,currentMonth);
}else{
currentMonth+=1;
renderCalender(currentYear,currentMonth);
}
}
});
//点击日历其中的日期后的操作
function callbackCalender(obj){
activeYear=obj.year;
activeMonth=obj.month;
activeNum=obj.num;
currentNum=obj.num;
console.log(obj.year,obj.month,obj.num)
//lineNum=getCalenderLine(obj.year,obj.month,obj.num);//该日期是第几行
if(activeMonth!=currentMonth){//点击是下个月或者上个月才更新日历
currentMonth=parseInt(activeMonth);
currentYear=parseInt(activeYear);
if(isWeek){//如果是周日历
renderWeekCaleder(true);
}else{//是月历
renderCalender(parseInt(activeYear),parseInt(activeMonth));
}
}
}
//上下拖拽日历down
calenderDom.addEventListener("mousedown",(ev)=>{
let downY=ev.clientY;
//鼠标移动日历move
function eventMove(ev){
let moveY=ev.clientY;
let disY=moveY-downY;
if(!isWeek && disY<0){//月历模式并且鼠标是向上移动的
calenderDom.style.height=(192-Math.abs(disY))+"px";
}else if(isWeek && disY>0){//周模式并且鼠标是向下移动的
calenderDom.style.height=Math.abs(disY)+"px";
}
//防止选中文字
window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();
}
document.addEventListener("mousemove",eventMove);
//鼠标点击日历后up
function eventUp(ev){
let moveY=ev.clientY;
let disY=moveY-downY;
if(!isWeek && disY<0){//月历模式并且鼠标是向上移动的
if(Math.abs(disY)<50){//如果鼠标移动距离小于50px,则回到原来的月历状态
calenderDom.style.height=192+"px";
}else{//大于50px,就收起来变成周日历
if(isWeek)return;//如果本来就是周历的话,直接return掉即可
isWeek=true;
calenderDom.style.height=32+"px";
preDom.innerHTML="上一周";
nextDom.innerHTML="下一周";
//渲染周日历
//如果是从月历状态切换成周历状态并且当前月份没有选中的日期,那么应该将当前日期设置为显示的月份的1号
if(currentYear!=activeYear || currentMonth!=activeMonth){
currentNum=1;
}else{
currentNum=activeNum;
}
renderWeekCaleder(false);
}
}else if(isWeek && disY>0){//周模式并且鼠标是向下移动的
if(Math.abs(disY)<10){//如果鼠标移动距离小于10px,就收起来变成周日历
calenderDom.style.height=32+"px";
}else{//大于10px,原来的月历状态
if(!isWeek)return;//如果本来就是月历的话,直接return掉即可
isWeek=false;
preDom.innerHTML="上一月";
nextDom.innerHTML="下一月";
calenderDom.style.height=192+"px";
//渲染月历
renderCalender(currentYear,currentMonth);
}
}
document.removeEventListener("mousemove",eventMove);
document.removeEventListener("mouseup",eventUp);
}
document.addEventListener("mouseup",eventUp);
});
//补零
function zeroize(num,n){
num=num.toString()
while(num.length<n){
num="0"+num;
}
return num;
}
网友评论