用ul和li模拟一个可以点击的日历

发布时间:2024年01月23日

用ul和li模拟一个可以点击的日历,因为需求是如果某天有事件则需要自动标红,效果图如下

在这里插入图片描述

注意!!!这处因为需要和时间选择器联动 ,所以把这个页面封装成一个组件,代码

<template>
  <div class="dates">
    <div id="calendar">
      <!-- 年份 月份 -->
      <!-- 星期 -->
      <ul class="weekdays">
        <li>一</li>
        <li>二</li>
        <li>三</li>
        <li>四</li>
        <li>五</li>
        <li>六</li>
        <li>日</li>
      </ul>
      <!-- 日期 -->
      <ul class="days">
        <!-- 核心 v-for循环 每一次循环用<li>标签创建一天 -->
        <li
          v-for="(item, i) in days"
          :key="i"
          @click="getDayTime(item.day, item)"
          :class="{ h5: h5 }"
        >
          <!--非本月-->
          <!--如果不是本月  改变类名加灰色-->
          <div
            v-if="item.day.getMonth() + 1 != currentMonth"
            class="other-month"
          >
            {{ dateFormat(item.day).split("-")[2] }}
          </div>
          <!--本月-->
          <div
            v-else
            :class="{
              liBox: true,
              active: item.day.getTime() <= new Date().getTime(),
              danger: item.isSelected,
            }"
          >
            <!-- active: dateFormat(item.day) == nowDay, -->
            <div class="dayBox">
              <div class="date">
                <span>{{ dateFormat(item.day).split("-")[2] }}</span>
                <!-- <div class="count"></div> -->
              </div>
            </div>
          </div>
        </li>
      </ul>
    </div>
  </div>
</template>

<script>
import moment from "moment";
import { dateFormat } from "@/util/date";

export default {
  data() {
    return {
      attenData: {}, //考勤数据
      nowTime: new Date(),
      timer: null,
      calendarData: [],
      currentDate: "",
      formLabelWidth: "140px",
      days: [], //当月日期
      newDate: "",
      nowDay: "",
      selectedDay: "",
      currentDay: 1,
      currentMonth: 1,
      currentYear: 1970,
      currentWeek: 1,
      h5: true,
      dateThings: [
        {
          date: "2023-12-01",
          things: "测试",
        },
        { date: "2023-12-05", things: "测试22" },
      ],
    };
  },
  props: {
    dateVal: {
      default: new Date(),
    },
  },
  watch: {
    dateVal() {
      this.initData();
      //   this.lastDate = getAllDays(this.dateVal).length - 24;
    },
  },
  created() {
    this.initData();
  },
  methods: {
    // 返回new Date()格式
    formatToDate(day) {
      let arr = day.split("-");
      return new Date(arr[0], arr[1] - 1, arr[2]);
    },
    initData() {
      this.nowDay = this.formatDate(
        this.dateVal.getFullYear(),
        this.dateVal.getMonth() + 1,
        this.dateVal.getDate()
      );
      var dateVal =
        typeof this.dateVal == "object"
          ? new Date(this.dateVal.getFullYear(), this.dateVal.getMonth(), 1)
          : new Date(
              this.dateVal.split("-")[0],
              this.dateVal.split("-")[1] - 1,
              1
            );
      this.currentDay = dateVal.getDate();
      this.currentYear = dateVal.getFullYear();
      this.currentMonth = dateVal.getMonth() + 1;
      this.currentWeek = dateVal.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;
      let firstWeekDay = new Date(
        this.currentYear,
        this.currentMonth - 1,
        1
      ).getDay();
      if (firstWeekDay == 0) {
        firstWeekDay = 7;
      }
      for (var i = firstWeekDay - 1; i > 0; i--) {
        var d2 = new Date(str);
        d2.setDate(d2.getDate() - i);
        var dayobjectSelf = {}; // 用一个对象包装Date对象  以便为以后预定功能添加属性
        dayobjectSelf.day = d2;
        this.days.push(dayobjectSelf); // 将日期放入data 中的days数组 供页面渲染使用
      }
      let maxLength = 35; //最多展示li的个数,5行
      this.h5 = true;
      if (
        ((firstWeekDay == 6 || firstWeekDay == 7) &&
          new Date(this.currentYear, this.currentMonth, 0).getDate() == 31) ||
        (firstWeekDay == 7 &&
          new Date(this.currentYear, this.currentMonth, 0).getDate() == 30)
      ) {
        // 如果本月1号是周六或周日并且这个月有31天,那么需要展示6行,如果本月1号是周日并且这个月有30天,也需要展示6行
        maxLength = 42; //6行
        this.h5 = false;
      }
      let alreadyLength = this.days.length;
      for (var j = 0; j < maxLength - alreadyLength; j++) {
        var d3 = new Date(str);
        d3.setDate(d3.getDate() + j);
        var dayobjectOther = {};
        dayobjectOther.day = d3;
        this.days.push(dayobjectOther);
      }

      // 如果某天有事件的话则标红
      for (let i = 0; i < this.days.length; i++) {
        const dateB = this.dateFormat(this.days[i].day);

        for (let j = 0; j < this.dateThings.length; j++) {
          const dateA = this.dateThings[j].date;

          if (dateB === dateA) {
            this.days[i].isSelected = true;
            break;
          }
        }
      }
    },

    dateFormat(date) {
      return dateFormat(date).slice(0, 10);
    },
    //返回字符串个格式的日期
    formatDate(year, month, day) {
      return (
        year +
        "-" +
        (month - 0 < 10 ? "0" + month : month) +
        "-" +
        (day - 0 < 10 ? "0" + day : day)
      );
    },
    getDayTime(time, item) {
      this.$emit("getDayTime", time, item);
    },
  },
};
</script>

<style lang="scss" scoped>
// 日历
#calendar {
  font-size: 12px;
  width: 100%;
  margin: 0 auto;
  // box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.1),
  //   0 1px 5px 0 rgba(0, 0, 0, 0.12);
}
.month {
  width: 100%;
  color: #333333;
}
.month ul {
  margin: 0;
  padding: 0;
  display: flex;
  justify-content: space-between;
  height: 35px;
}
.year-month {
  display: flex;
  align-items: center;
  justify-content: space-around;
  margin-top: 10px;
}
.choose-month {
  text-align: center;
  font-size: 12px;
}
.month ul li {
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 3px;
}
.weekdays {
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  li {
    display: inline-block;
    width: 14.2%;
    text-align: center;
    font-size: 14px;
    color: #555;
    font-weight: bold;
    line-height: 14px;
    padding: 12px 0;
    // border-right: 1px solid #ebeef5;
    box-sizing: border-box;
    // background: #fafafa;
    &:nth-child(7) {
      width: 14.8%;
    }
  }
}
.days {
  // padding: 10px;
  background: #ffffff;
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  li {
    display: inline-block;
    width: 14.2%;
    text-align: center;
    height: 31px; //6行
    // border-bottom: 1px solid #ebeef5;
    // border-right: 1px solid #ebeef5;
    cursor: pointer;
    position: relative;
    display: flex;
    align-items: center;
    flex-direction: column;
    justify-content: center;
    box-sizing: border-box;
    // 5行
    &.h5 {
      height: 36px;
    }

    &:hover {
      transition: background-color 0.2s;
      background-color: #f2f8fe;
    }
    &:nth-child(7n) {
      width: 14.8%;
      border-right: none;
    }
    .other {
      padding: 5px;
      color: gainsboro;
    }

    .liBox {
      width: 34px;
      height: 34px;
      // padding: 0 35px 0 16px;
      box-sizing: border-box;
      // display: flex;
      // align-items: center;
      // border: 2px solid transparent;

      &.active {
        // border: 2px solid #dbdbdb;
        .dayBox {
          .date {
            color: #fff;
            background: #37da3d;
          }
        }
      }
      &.checked {
        .dayBox {
          .date {
            color: #fff;
            background: #3377ff;
            border-radius: 50%;
          }
        }
      }
      &.danger {
        .dayBox {
          .date {
            color: #fff;
            background: #fe5e5e;
            border-radius: 50%;
          }
        }
      }
      .dayBox {
        width: 100%;
        height: 100%;
        display: flex;
        justify-content: center;
        align-items: center;
        .date {
          width: 25px;
          height: 25px;
          min-width: 25px;
          border-radius: 50%;
          text-align: center;
          font-size: 13px;
          color: #333;
          font-weight: 500;
          position: relative;
          //   color: #fff;
          //   background: #37f;
          border-radius: 50%;
          span {
            display: inline-block;
            width: 100%;
            height: 100%;
            line-height: 25px;
            font-size: 13px;
          }
          .count {
            width: 8px;
            height: 8px;
            border-radius: 4px;
            position: absolute;
            bottom: 0px;
            left: 50%;
            background: #3377ff;
            display: inline-block;
            transform: translateY(0) translateX(-50%);
          }
        }
        .ehecked {
          width: 24px;
          position: absolute;
          left: 0;
          top: 0;
        }
      }
    }
    .weather {
      display: flex;
      justify-content: space-between;
      align-items: center;
      img {
        width: 24px;
        margin-right: 10px;
      }
      span {
        font-size: 12px;
        color: #999;
        font-weight: 500;
        &.bad {
          color: #ed8079;
        }
      }
    }
  }
}
.days li {
  .other-month {
    color: #333;
    font-size: 20px;
    float: right;
    width: 100%;
    text-align: right;
    padding-right: 35px;
    box-sizing: border-box;
    display: none;
  }
}
.days li:hover > span > span {
  padding: 6px 10px;
  border-radius: 50%;
  background: #e1e1e1;
  color: #fff;
}
</style>
文章来源:https://blog.csdn.net/anny_mei/article/details/135773910
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。