使用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')
###判断本月内的签到情况
相关推荐
小镇程序员4 分钟前
vue2 src_Todolist全局总线事件版本
前端·javascript·vue.js
野槐6 分钟前
前端图像处理(一)
前端
程序猿阿伟14 分钟前
《智能指针频繁创建销毁:程序性能的“隐形杀手”》
java·开发语言·前端
疯狂的沙粒15 分钟前
对 TypeScript 中函数如何更好的理解及使用?与 JavaScript 函数有哪些区别?
前端·javascript·typescript
瑞雨溪24 分钟前
AJAX的基本使用
前端·javascript·ajax
力透键背27 分钟前
display: none和visibility: hidden的区别
开发语言·前端·javascript
程楠楠&M38 分钟前
node.js第三方Express 框架
前端·javascript·node.js·express
weiabc38 分钟前
学习electron
javascript·学习·electron
盛夏绽放1 小时前
Node.js 和 Socket.IO 实现实时通信
前端·后端·websocket·node.js
想自律的露西西★1 小时前
用el-scrollbar实现滚动条,拖动滚动条可以滚动,但是通过鼠标滑轮却无效
前端·javascript·css·vue.js·elementui·前端框架·html5