vue实现日历列表

项目中需要实现平铺一年的日历表,效果如下:

在这里插入图片描述

  • 实现的思路:做好一个月的日历组件,然后循环组件,渲染出一年的日历列表。

  • 实现过程如下:

  • utils.js公共方法

export const getNewDate = (date) => {
  let year = date.getFullYear();
  let month = date.getMonth();
  let day = date.getDate();
  return {
    year,
    month,
    day,
  };
};

export const getDate = (year, month, day) => {
  return new Date(year, month, day);
};

export const formatDate = (date) => {
  date = Number(date);
  return date < 10 ? `0${date}` : date;
};

export const colorList = [
  {
    name: "优",
    value: "#74B925",
  },
  {
    name: "良",
    value: "#F5E31C",
  },
  {
    name: "轻度",
    value: "#F2AF33",
  },
  {
    name: "中度",
    value: "#DC3838",
  },
  {
    name: "重度",
    value: "#A649A0",
  },
  {
    name: "严重",
    value: "#6C0E01",
  },
];

export const handleAQIColor = (value) => {
  // value = +value;
  let grade = "优";
  switch (true) {
    case value >= 0 && value <= 50:
      grade = "优";
      break;
    case value >= 51 && value <= 100:
      grade = "良";
      break;
    case value >= 101 && value <= 150:
      grade = "轻度";
      break;
    case value >= 151 && value <= 200:
      grade = "中度";
      break;
    case value >= 201 && value <= 300:
      grade = "重度";
      break;
    case value >= 301 && value <= 500:
      grade = "严重";
      break;
    default:
      grade = "无";
      break;
  }
  return grade;
};
  • date-calendar组件内容
<template>
  <div class="cc-calendar">
    <div class="calendar-title">
      <span>{{ year }}{{ month + 1 }}月</span>
    </div>
    <ul class="calendar-week">
      <li v-for="(item, index) in calendarTitleArr" :key="index" class="week-item">
        {{ item }}
      </li>
    </ul>
    <ul class="calendar-view">
    <!-- 动态设置背景颜色 -->
      <li
        v-for="(item, index) in visibleCalendar"
        :key="index"
        class="date-view"
        :style="{
          background: handleData(item.date) && isCurrentMonth(item.date) ? handleData(item.date).color : !isCurrentMonth(item.date) ? '#EAF2F2' : '#BFBFBF',
        }"
      >
        <span class="date-day" :class="[{ 'opacity-class': !isCurrentMonth(item.date) }]">
          {{ item.day }}
        </span>
        <span class="calendar-num">
          {{ handleData(item.date) && isCurrentMonth(item.date) ? handleData(item.date).pollution : "" }}
        </span>
      </li>
    </ul>
    <div class="color-box">
      <div v-for="item in colorList" :key="item.value">
        <span :style="{ background: item.value }"></span>
        <span>{{ item.name }}</span>
      </div>
    </div>
  </div>
</template>

<script>
import { getNewDate, getDate, formatDate, colorList, handleAQIColor } from "@/libs/utils.js";
export default {
  name: "date-calendar",
  props: {
    year: {
      type: [String, Number],
      default: 2022,
    },
    month: {
      type: [String, Number],
      default: 0,
    },
    list: {
      type: Array,
      default() {
        return [];
      },
    }
  },
  data() {
    return {
      calendarTitleArr: ["一", "二", "三", "四", "五", "六", "日"],
      colorList,
    };
  },
  computed: {
    visibleCalendar() {
      let calendatArr = [];
      let { year, month } = getNewDate(getDate(this.year, this.month, 1));

      let currentFirstDay = getDate(year, month, 1);

      // 获取当前月第一天星期几
      let weekDay = currentFirstDay.getDay();
      let startTime = null;
      if (weekDay == 0) {
        // 当月第一天是星期天
        startTime = currentFirstDay - 6 * 24 * 60 * 60 * 1000;
      } else {
        startTime = currentFirstDay - (weekDay - 1) * 24 * 60 * 60 * 1000;
      }
      // let monthDayNum;
      // 当第一天是周五 周六 周日 这个月绘制42天数据 否则为35天
      // if (weekDay == 5 || weekDay == 6 || weekDay == 0) {
      //   monthDayNum = 42;
      // } else {
      //   monthDayNum = 35;
      // }
      // for (let i = 0; i < monthDayNum; i++) {
      // 为了页面整齐排列 一并绘制42天
      for (let i = 0; i < 42; i++) {
        calendatArr.push({
          date: new Date(startTime + i * 24 * 60 * 60 * 1000),
          // year: year,
          // month: month + 1,
          year: new Date(startTime + i * 24 * 60 * 60 * 1000).getFullYear(),
          month: new Date(startTime + i * 24 * 60 * 60 * 1000).getMonth() + 1,
          day: new Date(startTime + i * 24 * 60 * 60 * 1000).getDate(),
        });
      }
      return calendatArr;
    },
  },
  methods: {
    handleData(date) {
      const data = [
        {
          time: "2022-08-01",
          pollution: "PM2.5",
          value: "35",
        },
        {
          time: "2022-05-02",
          pollution: "",
          value: "67",
        },
        {
          time: "2022-03-03",
          pollution: "PM10",
          value: "123",
        },
        {
          time: "2022-05-05",
          pollution: "SO2",
          value: "186",
        },
        {
          time: "2022-09-05",
          pollution: "NO",
          value: "256",
        },
        {
          time: "2022-12-12",
          pollution: "CO",
          value: "400",
        },
      ]
      data.forEach((item) => {
        if (item.pollution === "无") item.pollution = "";
        if (!item.value && item.value !== 0) {
          item.color = "#bfbfbf";
          return;
        }
        let list = colorList.filter((itm) => itm.name == handleAQIColor(item.value));
        item.color = list[0].value;
      });
      let { year, month, day } = getNewDate(date);
      let dateTime = year + "-" + formatDate(month + 1) + "-" + formatDate(day);
      let list = null;
      data.forEach((item) => {
        if (item.time == dateTime) {
          list = item;
        }
      });
      return list;
    },
    // 是否是当前月
    isCurrentMonth(date) {
      let { year: currentYear, month: currentMonth } = getNewDate(getDate(this.year, this.month, 1));
      let { year, month } = getNewDate(date);
      return currentYear == year && currentMonth == month;
    },
  },
  created() {},
};
</script>

<style lang="scss" scope>
body,
ul,
ol,
li {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

ul,
ol {
  list-style: none;
}
.cc-calendar {
  width: 441px;
  height: 100%;
  box-sizing: border-box;
  margin-bottom: 29px;
  .calendar-title {
    width: 100%;
    font-size: 16px;
    font-family: "Source Han Sans CN";
    font-weight: 500;
    color: #061a19;
    text-align: center;
    margin-bottom: 19px;
  }
  .calendar-week {
    display: flex;
    height: 28px;
    line-height: 28px;
    border: 1px solid #14c3ba;
    border-right: none;
    border-left: none;
    margin-bottom: 2px;
    .week-item {
      width: 67px;
      text-align: center;
      font-size: 14px;
      font-family: "Source Han Sans CN";
      color: #061a19;
      font-weight: 400;
    }
  }
  .calendar-view {
    display: flex;
    flex-wrap: wrap;
    border-top: 2px solid #e4e7ea;
    .date-view {
      width: 63px;
      height: 38px;
      border-right: 2px solid #e4e7ea;
      border-bottom: 2px solid #e4e7ea;
      box-sizing: border-box;
      position: relative;
      .date-day {
        padding: 8px;
        font-size: 12px;
        font-family: "Source Han Sans CN";
        font-weight: 400;
        color: #062927;
      }
      .calendar-num {
        position: absolute;
        left: 14px;
        bottom: 0;
        font-size: 14px;
        font-family: "Source Han Sans CN";
        font-weight: 400;
        color: #062927;
      }
    }
    .opacity-class {
      opacity: 0.5;
    }
  }
  .color-box {
    margin-top: 7px;
    display: flex;
    align-items: center;
    justify-content: flex-end;
    > div {
      display: flex;
      align-items: center;
      justify-content: center;
      > span:first-child {
        width: 30px;
        height: 14px;
      }
      > span:last-child {
        font-size: 14px;
        font-weight: 500;
        color: #1d2f2e;
      }
    }
    span {
      display: inline-block;
      width: 30px;
      margin-right: 1px;
      text-align: center;
    }
  }
}
</style>

  • 在父组件中引入date-calendar组件
<!-- 渲染12个月 -->
<dateCalendar year="2022" :month="index" v-for="(item, index) in 12" />
  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值