JS 输出日历完整篇
封装了一个方法,记录一下,演示地址:http://blog.xuxiangbo.com/demo/calendar.html
代码如下:
html内容:
<div class="demo">
<div class="timeBox">
<div class="timeHead">
<i class="erp erpweibiaoti--" @click="switchDate('py')"></i>
<i class="erp erpzuo" @click="switchDate('pm')"></i>
<p><span>{{head.year}}</span> 年 <span>{{head.month}}</span> 月</p>
<i class="erp erpzuo1" @click="switchDate('nm')"></i>
<i class="erp erpyou-" @click="switchDate('ny')"></i>
<a>{{head.date}}号 星期{{head.day}}</a>
</div>
<div class="timeDay">
<p v-for="(item, index) in weeks" v-show="index > 0" :key="index">{{item}}</p>
<p>日</p>
</div>
<div class="timeDateList">
<p
v-for="(item, index) in dateList"
:key="index"
:class="{today: item.name == '今天', hasTask: item.task, hover: currentHover == index, notCurrentMonth: item.month != 0}"
@click="onClick(item, index)"
>
<span>{{item.name}}</span>
</p>
</div>
</div>
<div class="taskBox">
<span class="editTask">{{task ? '编辑' : '添加'}}任务</span>
<p>时间:{{head.year + '-' + head.month + '-' + head.date}} <span style="margin-left: 20px;">星期{{head.day}}</span></p>
<p>任务:{{task || '无'}}</p>
</div>
</div>
body{
padding: 0;
margin: 0;
width: 100%;
height: 100%;
position: absolute;
display: flex;
justify-content: center;
align-items: center;
background: rgba(0, 0, 0, 0.05);
}
.demo{
width: 1000px;
height: 580px;
padding: 20px;
background: rgb(255, 255, 255);
display: flex;
justify-content: space-between;
align-items: flex-start;
}
.timeBox{
width: 600px;
height: 580px;
border-right: 1px solid rgba(0, 0, 0, 0.1);
user-select: none;
}
.timeHead{
width: 600px;
height: 50px;
display: flex;
justify-content: center;
align-items: center;
color: rgba(0, 0, 0, 0.6);
}
.timeHead i{
display: inline-block;
padding: 0 3px;
}
.timeHead i:hover{
color: rgb(0, 0, 0);
cursor: pointer;
}
.timeHead p span{
display: inline-block;
width: 30px;
text-align: center;
padding: 0 10px;
}
.timeHead a{
width: 100px;
position: relative;
left: 50px;
}
.timeDay,.timeDateList{
width: 560px;
padding: 0 10px;
display: flex;
justify-content: flex-start;
align-content: flex-start;
flex-wrap: wrap;
}
.timeDay p{
width: 80px;
text-align: center;
color: rgb(161, 161, 161);
font-weight: bold;
}
.timeDateList p{
width: 80px;
height: 80px;
margin: 0;
text-align: center;
line-height: 80px;
}
.timeDateList p span{
display: inline-block;
width: 50px;
height: 50px;
text-align: center;
line-height: 50px;
border-radius: 100%;
font-size: 14px;
transition: all 0.3s;
color: rgb(77, 77, 77);
}
.timeDateList p span:hover{
background: rgb(236, 236, 236);
cursor: pointer;
}
.timeDateList p.today span{
color: rgb(87, 119, 224);
}
.timeDateList p.hasTask span{
background: rgb(236, 236, 236);
}
.timeDateList p.hover span{
background: rgb(156, 177, 247);
color: rgb(255, 255, 255);
}
.timeDateList p.notCurrentMonth span{
color: rgb(204, 204, 204);
}
.taskBox{
width: 339px;
height: 520px;
font-size: 14px;
color: rgb(161, 161, 161);
padding: 30px;
position: relative;
}
.taskBox .editTask{
position: absolute;
top: 45px;
right: 20px;
color: rgb(101, 131, 228);
cursor: pointer;
user-select: none;
}
.taskBox .editTask:hover{
color: rgb(142, 167, 248);
}
const APP = new Vue({
el: '.demo',
data (){
return {
weeks: ['日','一', '二', '三', '四', '五', '六'],
dateList: [],
head: { year: '', month: '', date: '', day: '' },
currentHover: -1,
task: '',
}
},
mounted (){
let that = this;
that.draw();
},
methods: {
onClick (item, index){ // 切换日期
let that = this;
if(that.currentHover == index) return;
that.currentHover = index;
that.head = {
year: item.date.substr(0,4),
month: Number(item.date.substr(4,2)),
date: Number(item.date.substr(6,2)),
day: that.weeks[new Date(item.date.substr(0,4) + '-' + item.date.substr(4,2) + '-' + item.date.substr(6,2)).getDay()]
}
that.task = item.task;
// 点击到上个月或者下个月的日期
if(item.month != 0){
that.draw(that.head.year + '-' + that.head.month + '-' + that.head.date);
}
},
switchDate (type){
let that = this;
switch (type){
case 'py': // 上一年
that.draw((that.head.year - 1) + '-' + that.head.month + '-' + that.head.date);
break;
case 'pm': // 上一月
if(that.head.month == 1) that.draw((that.head.year - 1) + '-12-' + that.head.date);
else that.draw(that.head.year + '-' + (that.head.month - 1) + '-' + that.head.date);
break;
case 'nm': // 下一月
if(that.head.month == 12) that.draw((that.head.year + 1) + '-01-' + that.head.date);
else that.draw(that.head.year + '-' + (that.head.month + 1) + '-' + that.head.date);
break;
case 'ny': // 下一年
that.draw((that.head.year + 1) + '-' + that.head.month + '-' + that.head.date);
break;
default: break;
}
},
draw (time){ // 渲染日历
let that = this;
let result = [];
// 定义全局日期对象
let date = time ? new Date(time) : new Date();
// 获取当前日期
that.head = {
year: date.getFullYear(),
month: date.getMonth() + 1,
date: date.getDate(),
day: that.weeks[date.getDay()]
}
// 用到的方法
const timeFix = t => t > 9 ? String(t) : '0' + t; // month、day数字小于10的时候,前面补0
const monthLength = month => { // 当月有多少天,输入年月的数字,如:202104
let num = 0;
let y = Number(month.substr(0,4));
let m = Number(month.substr(4,2));
if([1,3,5,7,8,10,12].indexOf(m) > -1) num = 31;
else if(m == 2){
// 判定闰年:能被4整除且不能被100整除,或者能被400整除的为闰年
if(y % 4 == 0 && y % 100 != 0 || y % 400 == 0) num = 29;
else num = 28;
} else num = 30;
return num;
}
// 准备数据
// 计算本月1号是星期几
let day = new Date(date.getFullYear() + '-' + (date.getMonth() + 1) + '-01').getDay();
// 计算上月最后一天是几号(当月的天数)
let preMonthLength = monthLength(that.head.year + timeFix(that.head.month - 1));
// 用上月的末尾几天,补全当月前几天的空缺
for(let i = preMonthLength; i > preMonthLength - day + 1; i--){
let object = {
date: that.head.year + timeFix(that.head.month - 1) + timeFix(i), // 当前日期的输出格式:20210422
month: -1, // 当前日期所在月份,-1 = 上月,0 = 当月,1 = 下月
name: i // 当前日期显示的内容
}
result.push(object);
}
result.reverse();
// 输出本月的列表
for(let i = 1; i <= monthLength(that.head.year + timeFix(that.head.month)); i++){
let object = {
date: that.head.year + timeFix(that.head.month) + timeFix(i), // 当前日期的输出格式:20210422
month: 0, // 当前日期所在月份,-1 = 上月,0 = 当月,1 = 下月
name: i // 当前日期显示的内容
}
// 如果是今天,name 显示为 今天
let now = new Date();
if(object.date == now.getFullYear() + timeFix((now.getMonth() + 1)) + timeFix(now.getDate())) object.name = '今天';
result.push(object);
}
// 剩余的空白内容,使用下月的日期补全
// 日历一共显示 6 * 7 = 42天
// 43 - 已经有的天数 = 需要补全的天数
let num = 43 - result.length; // 要提前计算好剩余天数,再循环,不能把此变量放到for代码块里,否则会少渲染一天!
for(let i = 1; i < num; i++){
let object = {
date: that.head.year + timeFix(that.head.month + 1) + timeFix(i), // 当前日期的输出格式:20210422
month: 1, // 当前日期所在月份,-1 = 上月,0 = 当月,1 = 下月
name: i // 当前日期显示的内容
}
result.push(object);
}
// 绑定任务到日历,在此之前先获取到 tasklist
let taskList = [
{ date: '20210501', task: '放羊' },
{ date: '20210601', task: '杀鸡' },
{ date: '20210701', task: '喂猪' },
{ date: '20210801', task: '放牛' },
{ date: '20210901', task: '割草' },
{ date: '20211001', task: '去赛博坦进货' },
{ date: '20211101', task: '扫荡M78星云' },
{ date: '20211201', task: '火星一日游' },
{ date: '20220101', task: '奔月找嫦娥约会' },
{ date: '20220201', task: '杀鸡' },
{ date: '20220301', task: '练习两年半' },
]
result = result.map(item => {
taskList.map(task => {
if(task.date == item.date) item.task = task.task;
})
return item;
})
// 输出数据
that.dateList = result;
// 获取今天
result.map((item, index) => {
if(item.date == that.head.year + timeFix(that.head.month) + timeFix(that.head.date)){
that.currentHover = index;
that.task = result[index].task;
}
})
}
}
})