js实现日历组件(带节日和农历)
1,首先要下载 calendar.js 文件下载地址 calendar
下载好之后需要在文件里的最后一行加入默认导出 calendar,(不加也行)
calendar 是一个根据阳历转阴历的封装方法;
export default calendar;
// 在需要使用的地方导入
import calendar from '@/libs/calendar.js'
// 默认是 export 导出,不加的话引入需要加 { }引入
import { calendar } from '@/libs/calendar.js'
主模块 moment是一个日期转换的插件 地址
<template>
<div class="serviceCalendar">
<!-- 日历头部 -->
<calender-header
:currentYear="currentYear"
:currentMonth="currentMonth"
@pickPreNext="pickPreNext" />
<div class="dsys-box">
<!-- 星期 -->
<ul class="weekdays">
<li>星期一</li>
<li>星期二</li>
<li>星期三</li>
<li>星期四</li>
<li>星期五</li>
<li>星期六</li>
<li>星期日</li>
</ul>
<!-- 渲染日历 -->
<days-content
:days="days"
:currentMonth="currentMonth"
:newDate="newDate"
@getDayTime="getDayTime"
@reloadContent="reloadContent" />
</div>
</div>
</template>
<script>
import calenderHeader from './com/calenderHeader.vue'
import daysContent from './com/daysContent.vue'
import calendar from '@/libs/calendar.js'// 引入日历封装的方法
export default {
name: 'serviceCalendar',
components: {
calenderHeader,
daysContent,
},
data(){
return {
currentDay: 1,
currentMonth: new Date().getMonth() + 1,
currentYear: new Date().getFullYear(),
currentWeek: 1,
days: [],
newDate: '',
}
},
mounted(){
this.newDate = this.$moment(new Date()).format('YYYY-MM-DD');
// 在vue初始化时调用
this.initData(null);
},
methods: {
// 初始化数据
initData(cur) {
// var leftcount = 0 // 存放剩余数量
var date;
if (cur) {
date = new Date(cur);
} else {
var now = new Date();
var d = new Date(this.formatDate(now.getFullYear(), now.getMonth(), 1));
d.setDate(41);
date = new Date(this.formatDate(d.getFullYear(), d.getMonth() + 1, 1));
}
this.currentDay = date.getDate();
this.currentYear = date.getFullYear();
this.currentMonth = date.getMonth() + 1;
this.currentWeek = date.getDay(); // 1...6,0
if (this.currentWeek === 0) {
this.currentWeek = 7;
}
var str = this.formatDate(this.currentYear, this.currentMonth, this.currentDay);
this.days.length = 0;
// 初始化每月的第一周 this.currentWeek - 1 默认从周一开始
for (var i = this.currentWeek - 1; i >= 0; i--) {
var d2 = new Date(str);
d2.setDate(d2.getDate() - i);
const { name, isFestival } = this.solarToLunar(d2);
var dayobjectOther = {// 用一个对象包装Date对象 以便为以后预定功能添加属性
day: d2,// 阳历
specialDay: name,// 特殊节日、农历
isFestival,// 是否是节日节气
};
this.days.push(dayobjectSelf); // 将日期放入data 中的days数组 供页面渲染使用
}
// 其他周
for (var j = 1; j <= 42 - this.currentWeek; j++) {
var d3 = new Date(str);
d3.setDate(d3.getDate() + j);
const { name, isFestival } = this.solarToLunar(d3);
var dayobjectOther = {// 这里面可以填充你需要的字段
day: d3,// 阳历
specialDay: name,// 特殊节日、农历
isFestival,// 是否是节日节气
};
this.days.push(dayobjectOther);
}
// console.log(this.days);
},
// 点击那天那天处于选中状态
getDayTime(el, index) {
this.newDate = this.$moment(new Date(el)).format('YYYY-MM-DD');
console.log(el)
},
// 切换上月 下月
pickPreNext(type){
if(type == 'pre'){
this.pickPre(this.currentYear, this.currentMonth);
}else if(type == 'next'){
this.pickNext(this.currentYear, this.currentMonth);
}else{
this.initData(null);// 当前月
}
},
// 上月
pickPre: function (year, month) {
// setDate(0); 上月最后一天
// setDate(-1); 上月倒数第二天
// setDate(dx) 参数dx为 上月最后一天的前后dx天
var d = new Date(this.formatDate(year, month, 1));
d.setDate(0);
this.initData(this.formatDate(d.getFullYear(), d.getMonth() + 1, 1));
},
// 下月
pickNext: function (year, month) {
var d = new Date(this.formatDate(year, month, 1));
d.setDate(35);
this.initData(this.formatDate(d.getFullYear(), d.getMonth() + 1, 1));
},
// 返回 类似 2022-05-17 格式的字符串
formatDate: function (year, month, day) {
var y = year;
var m = month;
if (m < 10) m = "0" + m;
var d = day;
if (d < 10) d = "0" + d;
return y + "-" + m + "-" + d;
},
// 根据阳历 获取农历 curDya(需要获取的阳历日期)
solarToLunar(curDya) {
if(!curDya)return;
let solarDayArr = this.$moment(new Date(curDya)).format('YYYY-MM-DD').split('-');
let lunarDay = calendar.solar2lunar(solarDayArr[0], solarDayArr[1], solarDayArr[2])
// 农历日期 IMonthCn 月份 IDayCn 初几
// let lunarMD = lunarDay.IMonthCn + lunarDay.IDayCn
let lunarMD = lunarDay.IDayCn
// 公历节日\农历节日\农历节气
let festAndTerm = [];
festAndTerm.push(lunarDay.festival == null ? '' : ' ' + lunarDay.festival)
festAndTerm.push(lunarDay.lunarFestival == null ? '' : '' + lunarDay.lunarFestival)
festAndTerm.push(lunarDay.Term == null ? '' : '' + lunarDay.Term)
festAndTerm = festAndTerm.join('')
return festAndTerm == '' ? {name: lunarMD, isFestival: 0} : {name: festAndTerm, isFestival: 1}
},
// 刷新日历
reloadContent(){
this.getData();
}
}
}
</script>
<style lang="less" scoped>
.serviceCalendar{
font-size: 12px;
width: 100%;
margin: 0 auto;
// background: #ecf6ff;
// background: #f3f3f3;
}
.dsys-box{
width: 100%;
border: 1px solid #f3f3f3;
margin-top: 15px;
}
.weekdays {
margin: 0;
padding: 10px;
display: flex;
flex-wrap: wrap;
color: #666;
font-weight: 700;
background: #e3e3e3;
justify-content: space-around;
li {
display: inline-block;
width: 13.6%;
line-height: 40px;
text-align: center;
}
}
</style>
calenderHeader 模块
<template>
<div class="calenderHeader">
<!-- 年份 月份 -->
<div class="month">
<ul>
<li class="year-month">
{{ currentYear }}年
{{ currentMonth }}月
</li>
<li class="arrow hands">
<Button class="my-btn" type="primary" @click="pickPreNext('pre')">
<Icon type="ios-arrow-back" />
上月
</Button>
<Button class="my-btn" type="primary" @click="pickPreNext('cur')">
本月
</Button>
<Button class="my-btn" type="primary" @click="pickPreNext('next')">
下月
<Icon type="ios-arrow-forward" />
</Button>
</li>
</ul>
</div>
</div>
</template>
<script>
export default {
name: 'calenderHeader',
props: {
currentYear: {
type: [ String, Number ],
default: ''
},
currentMonth: {
type: [ String, Number ],
default: ''
},
},
methods: {
pickPreNext(type) {
this.$emit('pickPreNext', type)
},
},
};
</script>
<style lang="less" scoped>
.calenderHeader {}
.month {
width: 100%;
color: #333333;
ul {
margin: 0;
padding: 0;
// display: flex;
// justify-content: center;
// align-items: center;
height: 35px;
vertical-align: middle;
text-align: center;
position: relative;
li {
display: inline-block;
font-size: 18px;
font-weight: 700;
text-transform: uppercase;
margin: 0 10px;
&.year-month{
font-size: 24px;
vertical-align: middle;
}
}
.arrow{
position: absolute;
right: 0;
.my-btn{
margin: 0 5px;
}
}
}
}
</style>
daysContent 模块
<template>
<div class="daysContent">
<!-- 日期 -->
<ul class="days">
<!-- 核心 v-for循环 每一次循环用<li>标签创建一天 -->
<li v-for="(dayobject, i) in days" :key="dayobject.setDate">
<!--本月-->
<!--如果不是本月 改变类名加灰色-->
<div
v-if="dayobject.day.getMonth() + 1 != currentMonth"
class="day-box other-month"
>
<p class="solar">{{ `${dayobject.day.getMonth() + 1}月${dayobject.day.getDate()}日` }}</p>
<p class="lunar">{{ dayobject.specialDay }}</p>
<p class="content">{{ dayobject.content }}</p>
</div>
<!--如果是本月 还需要判断是不是这一天-->
<template v-else>
<!--今天 同年同月同日-->
<div
v-if="
dayobject.day.getMonth() == new Date().getMonth() &&
dayobject.day.getDate() == new Date().getDate()
"
:class="new Date(newDate).getDate() == new Date().getDate() ? 'day-box active' : 'day-box'"
@click="getDayTime(dayobject, i)"
>
<p class="solar">{{ `${dayobject.day.getMonth() + 1}月${dayobject.day.getDate()}日` }}</p>
<p class="lunar">{{ dayobject.specialDay }}</p>
<p class="content">{{ dayobject.content }}</p>
</div>
<div
v-else
:class="new Date(newDate).getDate() == dayobject.day.getDate() && new Date(newDate).getMonth() == dayobject.day.getMonth() ? 'day-box active' : 'day-box'"
@click="getDayTime(dayobject, i)"
>
<p class="solar">{{ `${dayobject.day.getMonth() + 1}月${dayobject.day.getDate()}日` }}</p>
<p class="lunar">{{ dayobject.specialDay }}</p>
<p class="content">{{ dayobject.content }}</p>
</div>
</template>
</li>
</ul>
</div>
</template>
<script>
export default {
name: 'daysContent',
components: {
addCalendar,
},
props: {
days: {
type: Array,
default: () => []
},
currentMonth: {
type: [ String, Number ],
default: ''
},
newDate: {
type: [ String, Number ],
default: ''
},
},
data(){
return {
curCalendarInfo: null,
}
},
methods: {
getDayTime(curInfo, index){
console.log(curInfo, index, '---------------点击了某天')
this.$emit('getDayTime', curInfo.day, index);
this.curCalendarInfo = curInfo;
},
}
}
</script>
<style lang="less" scoped>
.daysContent{}
.days {
// padding: 10px;
margin: 0;
display: flex;
flex-wrap: wrap;
li {
list-style-type: none;
display: inline-block;
width: 14.2%;
height: 100px;
text-align: center;
font-size: 12px;
color: #000;
border-left: 1px solid #f3f3f3;
border-bottom: 1px solid #f3f3f3;
.day-box{
width: 100%;
height: 100%;
padding: 10px;
}
.solar{
color: #2d8cf0;
}
.lunar{
color: #3068a3;
}
.content{
width: 100%;
text-align: left;
//超出两行省略号
display: -webkit-box;
overflow: hidden;
// text-overflow: ellipsis;
-webkit-box-orient: vertical;
line-clamp: 2;
-webkit-line-clamp: 2; //显示几行
}
.other-month {
p{
color: gainsboro;
// color: #999;
}
}
&:hover, .active {
background: #2d8cf0;
cursor: pointer;
p{
color: #fff;
}
}
}
}
</style>