js实现日历组件

宰父淳
2023-12-01

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>
 类似资料: