vue dayjs 构造日历组件

7 篇文章 0 订阅

在这里插入图片描述
在这里插入图片描述

<template>
  <!-- 选择年月 picker -->
  <van-popup v-model:show="state.showTime" position="bottom">
    <van-datetime-picker
      v-model="state.defaultDate"
      type="year-month"
      title="选择年月"
      :min-date="state.minDate"
      :max-date="state.maxDate"
      @cancel="state.showTime = false"
      @confirm="confirm"
    />
  </van-popup>

  <div class="root">
    <div class="common">
      <div class="common_header" @click="state.showTime = true">
        {{ state.date }} <van-icon name="arrow" />
      </div>

      <div class="date_box">
        <!-- 星期 -->
        <div class="week">
          <span v-for="(item, index) in week" :key="index">{{ item }}</span>
        </div>
        <!---->
        <div class="day">
          <div
            class="day_item"
            :class="[
              state.selectMonth != item.month
                ? 'dust'
                : state.activeIndex == index
                ? 'active'
                : '',
            ]"
            v-for="(item, index) in state.list"
            :key="index"
          >
            <span class="num" @click="handleToggle(index, item)">{{
              item.date
            }}</span>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { onMounted, reactive } from "vue";
import dayjs from "dayjs";

const emits = defineEmits(["select"]);

const week = ["日", "一", "二", "三", "四", "五", "六"];

const state = reactive({
  // picker
  minDate: new Date(2010, 1, 1),
  maxDate: new Date(),
  defaultDate: new Date(),

  // 日期数据
  list: [],

  // 默认当前日期
  date: dayjs().format("YYYY年MM月"),
  showTime: false,
  selectMonth: dayjs().format("M"),

  activeIndex: -1,
});

onMounted(() => {
  dateListInit();
  state.activeIndex = state.list.findIndex(
    (item) => item.dateString == dayjs().format("YYYY-MM-DD")
  );
  emits("select", dayjs().format("YYYY-MM-DD"));
});

// 点击日历日期
function handleToggle(index, item) {
  if (item.month != state.selectMonth) return;
  state.activeIndex = index;
  emits("select", item?.dateString);
}

// picker 确认
function confirm(val) {
  state.date = dayjs(val).format("YYYY年M月");
  state.selectMonth = dayjs(val).format("M");
  state.showTime = false;
  dateListInit(dayjs(val).format("YYYY"), dayjs(val).format("M"));
}

/**
 * 构造数据
 * @param {number} year
 * @param {number} month
 */
function dateListInit(
  year = Number(dayjs().format("YYYY")),
  month = Number(dayjs().format("M"))
) {
  //需要遍历的日历数组数据
  let dateList = [];
  //日历渲染开始日期
  let startDate = dayjs(`${year}-${month}`).day(0);
  //日历主体渲染结束日期
  let endDate = dayjs(`${year}-${month}`).endOf("month").day(6);
  //   循环构造数据
  while (startDate < endDate) {
    const dateString = startDate.format("YYYY-MM-DD");
    dateList.push({
      date: startDate.date(),
      month: startDate.month() + 1,
      year: startDate.year(),
      dateString,
    });
    startDate = startDate.add(1, "day");
  }
  state.list = dateList;
}
</script>

<style lang="scss" scoped>
.root {
  font-size: 28px;
  background-color: #f6f6f6;
  height: calc(100vh - var(--van-nav-bar-height));
  overflow: auto;
  padding: 20px 32px;
  box-sizing: border-box;

  .common {
    background: #ffffff;
    border-radius: 16px;
    margin-bottom: 20px;
    &_header {
      font-size: 28px;
      font-weight: bold;
      color: var(--van-primary-color);
      line-height: 40px;
      padding: 32px;
      border-bottom: 2px solid #eee;
    }

    .date_box {
      padding: 32px 0;
      .week {
        display: flex;
        align-items: center;
        text-align: center;
        margin-bottom: 24px;
        span {
          width: 98px;
        }
      }
      .day {
        display: flex;

        flex-wrap: wrap;

        &_item {
          width: 98px;
          height: 98px;
          display: flex;
          flex-direction: column;
          align-items: center;
          justify-content: center;

          &.dust {
            .num {
              color: #999999;
            }
          }
          &.active {
            .num {
              width: 60px;
              height: 60px;
              line-height: 60px;
              text-align: center;
              border-radius: 50%;
              background-color: #316eeb;
              color: #fff;
            }
          }

          .num {
            font-size: 26px;
            color: #333333;
            line-height: 36px;
          }
        }
      }

      .time_box {
        padding: 32px;
        .item {
          display: flex;
          align-items: center;
          margin-bottom: 32px;
          &:last-of-type {
            margin-bottom: 0;
          }
          .title {
            width: 60px;
            text-align: right;
            font-size: 26px;
            font-weight: bold;
            color: var(--van-primary-color);
            line-height: 36px;
          }
          .line {
            width: 4px;
            height: 70px;
            background: #eeeeee;
            margin-right: 32px;
            margin-left: 32px;
          }
          .content {
            background-color: #f8f8f8;
            border-radius: 16px;
            padding: 12px 24px;
            flex: 1;
            display: flex;
            flex-direction: column;
            .time {
              font-size: 26px;
              color: #333333;
              line-height: 36px;
            }
            .desc {
              font-size: 24px;
              color: #999999;
              line-height: 34px;
            }
          }
        }
      }
    }
  }
}
</style>

使用

<Calendar @select="select" />

function select(item) {
  console.log("1", item);
}

构造星期

在这里插入图片描述

onMounted(() => {
  let details = [];
  // 8 为下周  1 为当前周
  let num = true ? 8 : 1;
  for (let i = 0; i < 7; i++) {
    let temp = dayjs()
      .startOf("week")
      .add(`${i * 1 + num}`, "day")
      .format("YYYY-MM-DD");

    details.push({
      date: temp,
    });
  }
  console.log(details);
  // [
  //  {date: "2022-08-08"}
  //  {date: "2022-08-09"}
  //  {date: "2022-08-10"}
  //  {date: "2022-08-11"}
  //  {date: "2022-08-12"}
  //  {date: "2022-08-13"}
  //  {date: "2022-08-14"}
  // ]
});
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值