vue3实现简单的日历列表

2023-07-27  本文已影响0人  焚心123

new Date getFullYear() getMonth()
new Date('2023,'1',0) 这是获取1月的最后一天,月份是+1的,此时的月是2月,获取1月的最后一天

 const date = ref(new Date())
 const month = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
 const week = ["日", "一", "二", "三", "四", "五", "六"]

 <ul class="flexr flex-s-a">
        <li @click="pre">&lt;</li>
        <li>{{ date.getFullYear() }}年{{ month[date.getMonth()] }}月</li>
        <li @click="next">&gt;</li>
      </ul>

      <ul class="flexr f-w m-t-20">
        <li class="day" v-for="(item, index) in week" :key="index">
          {{ item }}
        </li>
      </ul>
    const pre = () => {
      // 返回上一个月的第一天起
      date.value = new Date(
        date.value.getFullYear(),
        date.value.getMonth() - 1,
        1
      )
     
    }
    const next = () => {
      date.value = new Date(
        date.value.getFullYear(),
        date.value.getMonth() + 1,
        1
      )

    }
 // 获取天数
    const getday = computed({
      get() {
        {
          const days = [] //{ day:'',text: "" ,botttmInfo:''}
          // 获取当前月份的第一天的周几,通过周几添加前面有几个空数据的
          const firstd =
            new Date(
              date.value.getFullYear(),
              date.value.getMonth(),
              1
            ).getDay() + ""
          // 获取当前月份的最后一天
          const lastd =
            new Date(
              date.value.getFullYear(),
              date.value.getMonth() + 1,
              0
            ).getDate() + ""

          // 添加当前前面展示的空
          for (let index = 0; index < firstd; index++) {
            days.push({ day: "", text: "", bottomInfo: "", date: "" })
          }
          //   添加天数
          for (let index = 1; index <= lastd; index++) {
            days.push({
              day: index,
              text: index,
              bottomInfo: "",
              date: new Date(
                date.value.getFullYear(),
                date.value.getMonth(),
                index
              ),
            })
          }
          return days
        }
      },
    })

     <ul class="flexr f-w m-t-20">
        <li class="day" v-for="(item, index) in week" :key="index">
          {{ item }}
        </li>
        <template v-for="(item, i) in getday" :key="'i' + i">
          <li
            :class="[
              'day',
              active === item.day
                ? 'ac'
                : '',
            ]"
            @click="db(item.day)"
          >
            <p :style="{ lineHeight: item.bottomInfo ? '' : '40px' }">
              {{ item.text ? item.text : item.day }}
            </p>
            <p
              v-if="item.bottomInfo && (item.text || item.day)"
            >
              {{ item.bottomInfo }}
            </p>
          </li>
        </template>
      </ul>
用一个变量进行存储当前的天数和月份(初始化,点击之后进行更新)
  const active = ref({
      m: date.value.getMonth() + 1,
      m1: date.value.getMonth() + 1,
      d: date.value.getDate(), //样式的切换
      s: date.value.getDate(), //当前的天数进行保存,对比
    })
  const db = (i) => {
      if (i < active.value.s && active.value.m >= date.value.getMonth() + 1)
        return

      active.value.d = i
      active.value.m1 = date.value.getMonth() + 1

      emit("change", {
        date:
          date.value.getFullYear() +
          "/" +
          (date.value.getMonth() + 1) +
          "/" +
          i,
      })
    }

  核心代码
        <li
            :class="[
              'day',
              active.d == item.day && active.m1 == date.getMonth() + 1
                ? 'ac'
                : '',
              (active.m == date.getMonth() + 1 &&
                item.day < new Date().getDate()) ||
              active.m > date.getMonth() + 1
                ? 'ag'
                : '',
            ]"
            @click="db(item.day)"
          >
<script>
import { computed, ref, watch } from "vue"
export default {
  name: "",
  components: {},
  props: {
    value: {
      typeof: Date,
      default: () => new Date(),
    },
    f: {
      typeof: Array,
      default: [],
    },
    fontSize: {
      typeof: String,
      default: "10px",
    },
  },
  emits: ["change", "formatter"],
  setup(props, { emit }) {
    const month = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
    const week = ["日", "一", "二", "三", "四", "五", "六"]

    const date = ref(props.value)

    const pre = () => {
      // 返回上一个月的第一天起
      date.value = new Date(
        date.value.getFullYear(),
        date.value.getMonth() - 1,
        1
      )
    }
    const next = () => {
      date.value = new Date(
        date.value.getFullYear(),
        date.value.getMonth() + 1,
        1
      )
    }

    // 获取天数
    const getday = computed({
      get() {
        {
          const days = [] //{ day:'',text: "" ,botttmInfo:''}
          // 获取当前月份的第一天的周几,通过周几添加前面有几个空数据的
          const firstd =
            new Date(
              date.value.getFullYear(),
              date.value.getMonth(),
              1
            ).getDay() + ""
          // 获取当前月份的最后一天
          const lastd =
            new Date(
              date.value.getFullYear(),
              date.value.getMonth() + 1,
              0
            ).getDate() + ""

          // 添加当前前面展示的空
          for (let index = 0; index < firstd; index++) {
            days.push({ day: "", text: "", bottomInfo: "", date: "" })
          }
          //   添加天数
          for (let index = 1; index <= lastd; index++) {
            days.push({
              day: index,
              text: index,
              bottomInfo: "",
              date: new Date(
                date.value.getFullYear(),
                date.value.getMonth(),
                index
              ),
            })
          }
          //直接在emit传递days就不用watch监听,但是用户可以修改day,导致页面问题
          // const d = days.map((item) => {
          //   return {
          //     text: item.text,
          //     bottomInfo: item.bottomInfo,
          //     date: item.text
          //       ? new Date(
          //           date.value.getFullYear(),
          //           date.value.getMonth(),
          //           item.text
          //         )
          //       : "",
          //   }
          // })

          emit("formatter", days)

          return days
        }
      },
    })

    // watch(
    //   () => props.f,
    //   (newV) => {
    //     console.log("newV", newV)
    //     newV.forEach((item) => {
    //       getday.value.forEach((val) => {
    //         val.text = item.text
    //         val.bottomInfo = item.bottomInfo
    //       })
    //     })
    //   }
    // )

    const active = ref({
      m: date.value.getMonth() + 1,
      m1: date.value.getMonth() + 1,
      d: date.value.getDate(), //样式的切换
      s: date.value.getDate(), //当前的天数进行保存,对比
    })
    const db = (i) => {
      if (i < active.value.s && active.value.m >= date.value.getMonth() + 1)
        return

      active.value.d = i
      active.value.m1 = date.value.getMonth() + 1

      emit("change", {
        date:
          date.value.getFullYear() +
          "/" +
          (date.value.getMonth() + 1) +
          "/" +
          i,
      })
    }

    return { week, date, month, pre, next, getday, active, db }
  },
}
</script>
<template>
  <div class="calendar">
    <h4>日历模板</h4>
    <div class="wrap">
      <ul class="flexr flex-s-a">
        <li @click="pre">&lt;</li>
        <li>{{ date.getFullYear() }}年{{ month[date.getMonth()] }}月</li>
        <li @click="next">&gt;</li>
      </ul>

      <ul class="flexr f-w m-t-20">
        <li class="day" v-for="(item, index) in week" :key="index">
          {{ item }}
        </li>
        <template v-for="(item, i) in getday" :key="'i' + i">
          <li
            :class="[
              'day',
              active.d == item.day && active.m1 == date.getMonth() + 1
                ? 'ac'
                : '',
              (active.m == date.getMonth() + 1 &&
                item.day < new Date().getDate()) ||
              active.m > date.getMonth() + 1
                ? 'ag'
                : '',
            ]"
            @click="db(item.day)"
          >
            <p :style="{ lineHeight: item.bottomInfo ? '' : '40px' }">
              {{ item.text ? item.text : item.day }}
            </p>
            <p
              v-if="item.bottomInfo && (item.text || item.day)"
              :style="{ fontSize }"
            >
              {{ item.bottomInfo }}
            </p>
          </li>
        </template>
      </ul>
    </div>
  </div>
</template>
<style lang="scss">
.calendar {
  width: 100%;
  height: 100%;
  text-align: center;
  .wrap {
    width: 600px;
    border: 1px solid #ccc;
    margin: 20px auto;
    box-sizing: border-box;
    padding: 20px 40px;
  }
  .flexr {
    display: flex;
    align-items: center;
  }
  .flex-s-a {
    justify-content: space-around;
  }
  .m-t-20 {
    margin-top: 20px;
  }
  .f-w {
    flex-wrap: wrap;
  }
  .day {
    width: calc(100% / 7);
    height: 60px;
    box-sizing: border-box;
    padding: 10px 0;
  }

  .ac {
    background: #f00;
    color: #000;
  }
  .ag {
    color: #ccc;
  }
}
</style>

上一篇 下一篇

猜你喜欢

热点阅读