您的当前位置:首页正文

vue3 手写日历组件

2024-11-30 来源:个人技术集锦

找了很久vue3的element样式一直没办法修改实现。只能手写日历了。借鉴了一些大佬的代码

调用:

再要使用的地方引入

import calendarelement from './calendarelement.vue'  //日历组件
 <div >     
        <calendarelement />  //日历
    </div>

效果:

<template>
  <div class="plan-zone">
    <div class="btn-group">
      <div class="left-btn">
        <el-button-group>
          <el-button @click="prevMonth" type="primary">上一个月</el-button>          
          <el-button type="primary" @click="goToCurrentDay">回到今天</el-button>
          <el-button @click="nextMonth" type="primary">下一个月</el-button>
        </el-button-group>
      </div>
      <div class="right-btn">
        <button class="new">长箱</button>
        <button class="ing">短箱</button>
        <button class="finish">双箱</button>
      </div>
    </div>
    <table class="parent-table">
      <thead>
        <th>周一</th>
        <th>周二</th>
        <th>周三</th>
        <th>周四</th>
        <th>周五</th>
        <th>周六</th>
        <th>周日</th>
      </thead>
      <tbody>
        <tr v-for="(week, windex) in weeks" :key="windex">
          <td v-for="(day, dindex) in week" :class="{ highlight: isToday(day.date) }" :key="dindex">
            <div class="content"
                 :class="{
                   faded: !isCurrentMonth(day.date),
                   hovered: isHovered(day.date),
                   selected: isSelected(day.date)
                 }"
                 @mouseenter="hoveredDay = day.date"
                 @mouseleave="hoveredDay = null"
                 @click="selectDay(day.date)"
            >
              <div class="top-day">{{ day.date.getDate() }}日  </div>
              <div class="middle-event">
                <div>
                  <span style="color: #409eef;">长箱</span>:<span>123</span>
                </div>
                </div>
              <div class="bottom-event">
                <div>
                  <span style="color: #ff974a;">短箱</span>:<span>123</span>
                </div>
              </div>
              <div class="bottom-event">
                <div>
                  <span style="color: #3dd599;">双箱</span>:<span>123</span>
                </div>
              </div>
          </div> 
          </td>
        </tr>
      </tbody>
    </table>
  </div>
</template>



<script setup>
import { ref, computed } from 'vue';

const current = ref(new Date());
const today = ref(new Date());

const getCurDate = () => {
  const date = new Date();
  const year = date.getFullYear();
  let month = date.getMonth() + 1;
  if (month < 10) {
    month = "0" + month;
  }
  return `${year}-${month}`;
};

const isToday = (date) => {
  const todayDate = new Date();
  return (
    date.getDate() === todayDate.getDate() &&
    date.getMonth() === todayDate.getMonth() &&
    date.getFullYear() === todayDate.getFullYear()
  );
};

const goToCurrentDay = () => {
  current.value = new Date(today.value);
};

const isCurrentMonth = (date) => {
  return date.getMonth() === current.value.getMonth();
};

const prevMonth = () => {
  current.value.setMonth(current.value.getMonth() - 1);
  current.value = new Date(current.value);
};

const nextMonth = () => {
  current.value.setMonth(current.value.getMonth() + 1);
  current.value = new Date(current.value);
};


const hoveredDay = ref(null);
const selectedDay = ref(null);

const isHovered = (date) => hoveredDay.value && hoveredDay.value.getTime() === date.getTime();
const isSelected = (date) => selectedDay.value && selectedDay.value.getTime() === date.getTime();
const selectDay = (date) => selectedDay.value = date;


const getMonthData = (year, month) => {
  const weeks = [];
  const firstDay = new Date(year, month - 1, 1);
  const lastDayOfCurrentMonth = new Date(year, month, 0);
  const lastDayOfPrevMonth = new Date(year, month - 1, 0);

  let startDayOfWeek = firstDay.getDay() === 0 ? 7 : firstDay.getDay();
  let dayCount = 1;
  let prevMonthDayCount = lastDayOfPrevMonth.getDate() - startDayOfWeek + 2;

  for (let i = 0; i < 6; i++) {
    const week = [];
    for (let j = 0; j < 7; j++) {
      if (i === 0 && j < startDayOfWeek - 1) {
        week.push({ date: new Date(year, month - 2, prevMonthDayCount++) });
      } else if (dayCount > lastDayOfCurrentMonth.getDate()) {
        week.push({
          date: new Date(year, month, dayCount++ - lastDayOfCurrentMonth.getDate()),
        });
      } else {
        week.push({ date: new Date(year, month - 1, dayCount++) });
      }
    }
    weeks.push(week);
  }
  return weeks;
};

const weeks = computed(() => getMonthData(current.value.getFullYear(), current.value.getMonth() + 1));

</script>

 <style lang="scss" scoped>
.faded {
  opacity: 0.3;
}
.highlight {
  background: rgba(255, 220, 40, 0.15);
}
.plan-zone {
  margin-top: 10px;
  .btn-group {
    display: flex;
    justify-content: space-between;
    .right-btn {
      button.new {
        background-color: #fff;
        border: 1px solid #fff;
        color: #409eef;
        position: relative;
        &::before {
          content: "";
          width: 8px;
          height: 8px;
          border-radius: 50%;
          position: absolute;
          top: 7px;
          left: -3px;
          background-color: #409eef;
        }
      }
      button.ing {
        background-color: #fff;
        border: 1px solid #fff;
        color: #ff974a;
        position: relative;
        &::before {
          content: "";
          width: 8px;
          height: 8px;
          border-radius: 50%;
          position: absolute;
          top: 7px;
          left: -3px;
          background-color: #ff974a;
        }
      }
      button.finish {
        background-color: #fff;
        border: 1px solid #fff;
        color: #3dd599;
        position: relative;
        &::before {
          content: "";
          width: 8px;
          height: 8px;
          border-radius: 50%;
          position: absolute;
          top: 7px;
          left: -3px;
          background-color: #3dd599;
        }
      }
    }
  }
}
.parent-table {
  border-collapse: collapse;
  table-layout: fixed;
  width: 100%;
  margin-top: 20px;
  th,
  td {
    width: 14.4%;
    border: 1px solid #ddd;
  }
  td {
    padding: 2px 3px;
    .content {
      position: relative;
      min-height: 80px;
      transition: background-color 0.3s ease;
    }
    vertical-align: top;
    .top-day {
      text-align: right;
      font-size: 16px;
    }
  }
}
.table-date {
  display: flex;
  > div {
    flex: 1;
  }
}
.hovered {
  background-color: rgba(64, 56, 180, 0.1);
}
.selected {
  background-color: rgba(70, 168, 40, 0.2);
}
</style>

显示全文