使用Vue3+Typescript手写一个日历签到组件

设计理念

昨天写了个简单美观的日历签到组件,使用的是Vue3+TypeScript,大概逻辑是先找到本月份第一天是周几,然后开始填充月份日期:weeksArray:[[]]:之后渲染到表格中,对于签到事件触发则先判断是否是今天且还未没有签到,没有就发送请求给后端的接口,然后签到就完成了。

设计UI

代码

详情请看俺滴代码:

html 复制代码
<template>
  <div class="calendar">
    <h1>{{ month }}月每日签到</h1>
    <p>
      您已经签到了<em>{{ signedDates.length }}</em
      >天,
      <span v-show="!isTodaySigned">今天还没签到哦!</span>
      <span v-show="isTodaySigned">今日已经签到!</span>
    </p>
    <a-divider style="margin-top: 0" />
    <table>
      <thead>
        <tr>
          <th v-for="weekday in weekdays" :key="weekday">{{ weekday }}</th>
        </tr>
      </thead>
      <tbody>
        <tr v-for="week in weeks" :key="week">
          <td
            v-for="day in week"
            :key="day"
            :class="{ today: isToday(day), signed: isSigned(day) }"
            @click="sign(day)"
          >
            {{ day }}
          </td>
        </tr>
      </tbody>
    </table>
  </div>
</template>

<script lang="ts" setup>
import { computed, onMounted, reactive, ref } from "vue";
import message from "@arco-design/web-vue/es/message";
import { SignAddRequest, SignControllerService } from "../../generated";

const currentDate = ref<Date>(new Date()); // 今天
const signedDates = ref(["2023-12-01", "2023-12-05"]); // 已签到的日期
const month = ref(new Date().getMonth() + 1); //本月
const weekdays = computed(() => {
  const weekdays = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
  return weekdays.map((weekday) => weekday.slice(0, 2));
}); //表头
//本月日期情况
const weeks = computed(() => {
  const year = currentDate.value.getFullYear();
  const month = currentDate.value.getMonth();
  const firstDayOfMonth = new Date(year, month, 1).getDay();
  const daysInMonth = new Date(year, month + 1, 0).getDate();
  const weeksArray: Array<Array<any>> = [[]];
  let currentWeek = 0;

  for (let i = 0; i < firstDayOfMonth; i++) {
    weeksArray[currentWeek].push("");
  }

  for (let day = 1; day <= daysInMonth; day++) {
    if (weeksArray[currentWeek].length === 7) {
      weeksArray.push([]);
      currentWeek++;
    }
    weeksArray[currentWeek].push(day);
  }

  return weeksArray;
});
// 当前表格是不是今天
const isToday = (day: number) => {
  const today = new Date();
  return (
    day === today.getDate() &&
    currentDate.value.getMonth() === today.getMonth() &&
    currentDate.value.getFullYear() === today.getFullYear()
  );
};
// 当前表格是否已经被签到了
const isSigned = (day: number) => {
  const year = currentDate.value.getFullYear();
  const month = currentDate.value.getMonth() + 1;
  const date = day.toString().padStart(2, "0");
  const dateString = `${year}-${month}-${date}`;
  return signedDates.value.includes(dateString);
};
// 今天是否已签
const isTodaySigned = computed(() => {
  const today = new Date();
  const day = today.getDate();
  return isSigned(day);
});
// 签到
const sign = (day: number) => {
  if (isToday(day) && !isSigned(day)) {
    const year = currentDate.value.getFullYear();
    const month = currentDate.value.getMonth() + 1;
    const date = day.toString().padStart(2, "0");
    const dateString = `${year}-${month}-${date}`;
    signedDates.value.push(dateString);
    message.success("签到成功,业精于勤荒于嬉,请继续坚持!!!");
    addSign(dateString);
  }
};
//发送签到请求参数
// 发给后端请求当前登录用户本月的签到情况
const addSign = async (date: string) => {
  SignControllerService.addSignUsingPost(date);
};
const init = async () => {
  console.log("签到组件加载完成");
  const res = await SignControllerService.getSignedDateUsingGet();
  if (res.code === 0) {
    signedDates.value = res.data as string[];
  }
};
onMounted(() => {
  init();
});
</script>

<style scoped>
.calendar {
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.calendar h1 {
  font-family: 华文仿宋;
  text-align: center;
  margin-bottom: 0px;
}

.calendar p {
  font-size: large;
  font-family: 华文仿宋;
  text-align: center;
}

em {
  color: lightgreen;
  font-size: large;
  font-weight: bold;
  margin: 0 5px 0 1px;
}

table {
  border-collapse: collapse;
  width: 95%;
  margin: 0 auto;
}

th,
td {
  border: 1px solid #ccc;
  padding: 10px;
  text-align: center;
}

th {
  background-color: #f0f0f0;
}

td.today {
  background-color: #eaf6ff;
  cursor: pointer;
}

td.signed {
  background-color: #b3e5fc;
}

td.signed:hover {
  background-color: #80d4f7;
}
</style>

后端主要的SQL语言

主要的SQL语言是:用DATE_FORMAT(CURDATE(), '%Y%m)判断年月是否一样。

sql 复制代码
SELECT createTime
FROM sign
WHERE userId = 1727616588754034690
  and DATE_FORMAT(createTime, '%Y%m') = DATE_FORMAT(CURDATE(), '%Y%m')
###判断本月内的签到情况
相关推荐
難釋懷2 小时前
Redis主从-主从数据同步原理
前端·数据库·redis
a1117762 小时前
Markdown生成思维导图(html 开源)
前端·开源·html
我命由我123452 小时前
React - state、state 的简写方式、props、props 的简写方式、类式组件中的构造器与 props、函数式组件使用 props
前端·javascript·react.js·前端框架·html·html5·js
钰衡大师2 小时前
Vue 3 源码学习教程
前端·vue.js·学习
C澒2 小时前
React + TypeScript 编码规范|统一标准 & 高效维护
前端·react.js·typescript·团队开发·代码规范
时光少年2 小时前
Android 视频分屏性能优化——GLContext共享
前端
IT_陈寒3 小时前
JavaScript开发者必知的5个性能杀手,你踩了几个坑?
前端·人工智能·后端
跟着珅聪学java3 小时前
Electron 精美菜单设计
运维·前端·数据库
日光倾3 小时前
【Vue.js 入门笔记】闭包和对象引用
前端·vue.js·笔记
EstherNi3 小时前
左右两侧定位的效果,vue3
javascript·vue.js