vue2日历实现

<template>
  <div class="calendar">
    <div class="calendar-header">
      <button @click="prevMonth">上一月</button>
      <span>{{ currentYear }}年{{ currentMonth + 1 }}月</span>
      <button @click="nextMonth">下一月</button>
      <button @click="toCurrentMonth">当前月</button>
    </div>
    <table>
      <thead>
        <tr>
          <th v-for="day in weekDays" :key="day">{{ day }}</th>
        </tr>
      </thead>
      <tbody>
        <tr v-for="(week, index) in weeks" :key="index">
          <td
            v-for="(day, i) in week"
            :key="i"
            :class="{ 'other-month': !day.isCurrentMonth, today: isToday(day) }"
          >
            <div class="day-cell" @click="today(day)">
              {{ day.date }}
              <div v-if="isSpecialDay(day)" class="red-dot"></div>
            </div>
          </td>
        </tr>
      </tbody>
    </table>
  </div>
</template>

<script>
export default {
  props: ["calendarOndate"], // 接收父组件传递的日期数组
  data() {
    return {
      currentDate: new Date(), // 默认显示当前月
      weekDays: ["日", "一", "二", "三", "四", "五", "六"],
    };
  },
  computed: {
    currentYear() {
      return this.currentDate.getFullYear();
    },
    currentMonth() {
      return this.currentDate.getMonth();
    },
    weeks() {
      const year = this.currentYear;
      const month = this.currentMonth;
      const firstDay = new Date(year, month, 1);
      const firstDayWeekday = firstDay.getDay();

      // 计算日历起始日期(包含上月末尾几天)
      const startDate = new Date(firstDay);
      startDate.setDate(1 - firstDayWeekday);

      // 生成6周(42天)的日期数据
      const days = [];
      for (let i = 0; i < 42; i++) {
        const date = new Date(startDate);
        date.setDate(startDate.getDate() + i);
        days.push({
          year: date.getFullYear(),
          month: date.getMonth(),
          date: date.getDate(),
          isCurrentMonth: date.getMonth() === month,
        });
      }

      // 将日期按周分组
      return this.chunkArray(days, 7);
    },
  },
  methods: {
    // 判断某一天是否有任务
    isSpecialDay(day) {
      const formattedDate = this.formatDate(day); // 格式化日期为 YYYY-MM-DD
      return this.calendarOndate.includes(formattedDate); // 判断是否在 calendarOndate 中
    },

    // 格式化日期为 YYYY-MM-DD
    formatDate(day) {
      const year = day.year;
      const month = String(day.month + 1).padStart(2, "0");
      const date = String(day.date).padStart(2, "0");
      return `${year}-${month}-${date}`;
    },

    // 点击某一天
    today(day) {
      const formattedDate = this.formatDate(day);
      this.$emit("checkTodayNote", { Msg: { date: formattedDate } }); // 触发父组件事件
    },

    // 切换到上一月
    prevMonth() {
      this.currentDate = new Date(this.currentYear, this.currentMonth - 1, 1);
      this.$emit(
        "getMonthList",
        this.formatDate({
          year: this.currentYear,
          month: this.currentMonth,
          date: 1,
        })
      );
    },

    // 切换到下一月
    nextMonth() {
      this.currentDate = new Date(this.currentYear, this.currentMonth + 1, 1);
      this.$emit(
        "getMonthList",
        this.formatDate({
          year: this.currentYear,
          month: this.currentMonth,
          date: 1,
        })
      );
    },

    // 切换到当前月
    toCurrentMonth() {
      this.currentDate = new Date();
      this.$emit(
        "getMonthList",
        this.formatDate({
          year: this.currentYear,
          month: this.currentMonth,
          date: 1,
        })
      );
    },

    // 判断是否是今天
    isToday(day) {
      const today = new Date();
      return (
        day.year === today.getFullYear() &&
        day.month === today.getMonth() &&
        day.date === today.getDate()
      );
    },

    // 将数组按指定大小分块
    chunkArray(arr, size) {
      return Array.from({ length: Math.ceil(arr.length / size) }, (v, i) =>
        arr.slice(i * size, i * size + size)
      );
    },
  },
};
</script>

<style scoped>
.calendar {
  font-family: Arial;
  width: 350px;
  margin: 20px;
}
.calendar-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 10px;
}
table {
  width: 100%;
  border-collapse: collapse;
}
th,
td {
  padding: 10px;
  text-align: center;
  border: 1px solid #ddd;
}
.other-month {
  color: #ccc;
}
.day-cell {
  position: relative;
  min-height: 40px;
  cursor: pointer;
}
.red-dot {
  position: absolute;
  top: 2px;
  right: 2px;
  width: 6px;
  height: 6px;
  background-color: red;
  border-radius: 50%;
}
.today {
  background-color: lightblue;
}
button {
  padding: 5px 10px;
  cursor: pointer;
}
</style>

posted @ 2025-03-13 01:47  凯宾斯基  阅读(173)  评论(0)    收藏  举报