日历选择组件(打卡,日期计划,日期选择,特别日期标志)-VUE3

news2024/11/30 8:58:49

自己封装的目的:

使用场景:打卡,日期计划,日期选择,特别日期标志

根据自己的需求可以定制化何样式

不依赖任何第三方插件或者组件

效果图:

1、日历组件封装

<template>
	<div class="calendar">
		<div class="year-month">
			<div class="arrow up-page" @click="upPage"></div>
			<span>{{year}}年{{month}}月</span>
			<div class="arrow next-page"  @click="nextPage"></div>
		</div>
		<div class="week">
			<div class="item" v-for="item of weeks">{{item}}</div>
		</div>
		<template v-for="line of dates">
			<div class="week">
				<div v-for="item of line" @click="onClick(item)" :class="['item' ,
				{'current-month':month==item.month},
				{'today':today==`${item.month}-${item.date}`},
				{'clickFlag':clickFlag===item.timeStamp},
				{'select':selectDates.find(t=> t>item.timeStamp&&t<item.timeStamp+oneDayTimeStamp)}]">{{item.date}}</div>
			</div>
		</template>
	</div>
</template>

<script setup>
	import { watchEffect, ref, onBeforeMount } from "vue"
	const today = `${new Date().getMonth()+1}-${new Date().getDate()}`
	const weeks = ["日", '一', '二', '三', '四', '五', '六']
	const oneDayTimeStamp = 86400 * 1000
	const dates = ref([])
	const month = ref("")
	const year = ref("")
	const clickFlag = ref("")
	const emit = defineEmits(["onSelect"])
	const props = defineProps({
		defaultDate: {
			type: [String, Number],
			default: Date.now()
		},
		selectDates: {
			type: Array,
			default () {
				const now = Date.now();
				const oneDayTimeStamp = 86400 * 1000
				return [now - oneDayTimeStamp, now, now + oneDayTimeStamp, now + oneDayTimeStamp * 3]
			}
		},
	})
	onBeforeMount(() => {
		let firstTimestamp = getCurrentPageTimestampOf1(props.defaultDate)
		getList(firstTimestamp)
	})

	function upPage() {
		let firstTimestamp = getFirstTimestampByUp()
		getList(firstTimestamp)
	}

	function nextPage() {
		let firstTimestamp = getFirstTimestampByNext()
		getList(firstTimestamp)
	}

	// 获取当前页日期列表
	function getList(timestamp) {
		const temp = []
		const list = []
		// 包含一个足月的最小周期为42天
		const pageT = 42
		for (let i = 0; i < pageT; i++) {
			temp.push(coverToDate(timestamp, i))
		}

		while (temp.length > 0) {
			list.push(temp.splice(0, 7))
		}
		removeLine(list)
		month.value = list[1][1].month
		year.value = list[1][1].year
		dates.value = list
	}

	// 获取上一页的第一个元素的时间戳
	function getFirstTimestampByUp() {
		const firstObj = dates.value[0][0]
		let timestamp = 0
		//  第一行第一个元素是1号,返回firstObj前一天的时间戳 ,
		//  否则直接返回firstObj的时间戳
		if (firstObj.date === 1) {
			timestamp = firstObj.timeStamp - oneDayTimeStamp
		} else {
			timestamp = firstObj.timeStamp
		}

		return getCurrentPageTimestampOf1(timestamp)
	}

	// 获取下一页的第一个元素的时间戳
	function getFirstTimestampByNext() {
		let len = dates.value.length
		const lastLine = dates.value[len - 1]
		// 最后一行包含1号,直接返回第一个元素的时间戳,
		// 否则返回最后一个元素的时间戳 + 一天的时间戳
		const includeDateOf1 = lastLine.find(item => item.date === 1)
		if (includeDateOf1) {
			return lastLine[0].timeStamp
		} else {
			return lastLine[6].timeStamp + oneDayTimeStamp
		}
	}

	// 删除掉不是属于当前月的行
	function removeLine(list) {
		if (list.length > 5) {
			let index = list.slice(1).findIndex(line => line.some(item => item.date == 1))
			if (index != -1) {
				const startIndex = index + 1
				// 最后一行的第一天
				const lastLineOf1 = list[startIndex][0].date
				if (lastLineOf1 === 1) {
					list.splice(startIndex)
				} else {
					list.splice(startIndex + 1)
				}
			}
		}
	}

	// 获取当页的第一个日期的时间戳
	function getCurrentPageTimestampOf1(timestamp) {
		const time = new Date(timestamp)
		const year = time.getFullYear()
		const month = time.getMonth() + 1
		// 当月的第一天
		const dateOf1 = new Date(`${year}/${month}/1`)
		// 当月的第一天,是星期几
		const weekOf1 = dateOf1.getDay()
		// 当页的第一天时间戳
		const firstTimestampOfPage = dateOf1.getTime() - weekOf1 * oneDayTimeStamp
		return firstTimestampOfPage
	}

	// 时间戳转成日期对象
	function coverToDate(firstTimestampOfPage, index) {
		const timeStamp = firstTimestampOfPage + index * oneDayTimeStamp
		let obj = new Date(timeStamp)
		let date = obj.getDate()
		const week = obj.getDay()
		const month = obj.getMonth() + 1
		const year = obj.getFullYear()
		return { year, month, date, week, timeStamp }
	}

	function onClick(e) {
		clickFlag.value = e.timeStamp
		emit("onSelect", e)
	}
</script>

<style lang="scss" scoped>
	.calendar {
		height: 642rpx;
		margin: 20rpx;
		display: flex;
		flex-direction: column;
		justify-content: space-around;
		border-radius: 10rpx;
		background-color: #FFF;
		
		.year-month{
			height: 88rpx;
			display: flex;
			justify-content: space-between;
			align-items: center;
			border-bottom: 2rpx solid #d7d7d7;
			.arrow{
				height: 30rpx;
				width: 30rpx;
				border: 2rpx solid #666;
				border-bottom: none;
				border-right: none;
			}
			.up-page{
				margin-left: 20rpx;
				transform: rotate(-45deg);
			}
			.next-page{
				margin-right: 20rpx;
				transform: rotate(135deg);
			}
		}

		.week {
			height: 70rpx;
			display: flex;
			color: #CCCCCC;
			font-size: 28rpx;
			justify-content: space-around;
			align-items: center;

			.item {
				position: relative;
				width: 70rpx;
				height: 70rpx;
				line-height: 70rpx;
				text-align: center;
				box-sizing: border-box;

				&.current-month {
					color: #666;
				}

				&.today::before {
					position: absolute;
					bottom: 2rpx;
					left: 29rpx;
					content: "";
					display: block;
					width: 12rpx;
					height: 12rpx;
					border-radius: 50%;
					background: #6C93FF;
				}

				&.clickFlag {
					color: #6C93FF ;
					font-weight: 600;
					border: 2rpx solid #6C93FF;
					border-radius: 50%;
				}

				&.select {
					color: #FFF;
					background: #6C93FF;
				}
			}
		}
	}
</style>

2、使用日历组件

<template>
	<div>
		<Calendar @onSelect="onSelect"></Calendar>
		<div>日历选择:{{selectDate}}</div>
	</div>
</template>

<script setup>
	import { ref } from 'vue'
	import Calendar from "@/components/calendar.vue"
	const selectDate = ref("")

	function onSelect(e) {
		selectDate.value = e		
	}
</script>

<style>
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1824699.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

把Vue项目从Window系统迁移到Mac系统的方案

不能启动vue ui 直接运行&#xff0c;会报错如下&#xff1a; failed to load config from /Users/xiaochen/IdeaProjects/ChatViewer-frontend/vite.config.tserror when starting dev server: Error: You installed esbuild for another platform than the one youre curre…

关于LLM:揭秘token与embedding的机制

「GPT4 Turbo 的上下文长度为 128K token」 「Claude 2.1 的上下文长度为 200K token」 听起来像是一些重要的细节&#xff0c;那么token到底是什么&#xff1f; 请看一句话——It’s over 9000&#xff01; 我们可以将其表示为 [“It’s”, “over”, “9000!”] 每个数组…

救命!接手了一个老项目,见到了从业10年以来最烂的代码!

后台回复“书籍”&#xff0c;免费领取《程序员书籍资料一份》 后台回复“5000”&#xff0c;免费领取面试技术学习资料一份 在程序员这个行业从业快10年了&#xff0c;每过几个月回头看看自己写的代码&#xff0c;都会觉得写的也太烂了&#xff0c;不敢想象是自己之前写的。…

CorelDRAW2024破解版看这里!免费分享

亲爱的设计爱好者们&#xff0c;你们好呀&#xff01;今天我要给大家种草一款神奇的软件——CorelDRAW 2024&#xff01;&#x1f929;&#x1f389; 作为一位软件技术爱好者&#xff0c;我一直在寻找那些能让我们事半功倍的工具。最近&#xff0c;我在数字设计领域发现了一个…

【2024最新华为OD-C/D卷试题汇总】[支持在线评测] 目录管理器(200分) - 三语言AC题解(Python/Java/Cpp)

🍭 大家好这里是清隆学长 ,一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-C/D卷的三语言AC题解 💻 ACM银牌🥈| 多次AK大厂笔试 | 编程一对一辅导 👏 感谢大家的订阅➕ 和 喜欢💗 📎在线评测链接 目录管理器(200分) 🌍 评测功能需要订阅专栏后私信联系清隆…

QShop商城-短信通知配置

QShop商城-短信通知配置 本系统短信通知配置可选阿里云/腾讯云,二者二选一即可. 阿里云短信 一、登录阿里云短信平台 阿里云短信平台管理地址&#xff1a;https://dysms.console.aliyun.com/dysms.html 二、账户ID和秘钥&#xff08;AccessKeyId 和 AccessKeySecret&#x…

认识一些分布函数-Frechet分布及其应用

1. 何为Frechet分布 Frechet分布也称为极值分布(EVD)类型II,用于对数据集中的最大值进行建模。它是四种常用极值分布之一。另外三种是古贝尔分布、威布尔分布和广义极值分布(Gumbel Distribution, the Weibull Distribution and the Generalized Extreme Value Distributi…

3D 图片悬停效果

3D 图片悬停效果 效果展示 CSS 知识点 background 属性的综合运用transform 属性的综合运用 页面整体布局 <div class"box"><span style"--i: 0"></span><span style"--i: 1"></span><span style"--i…

数据资产管理的未来趋势:洞察技术前沿,探讨数据资产管理在云计算、大数据、区块链等新技术下的发展趋势

一、引言 随着信息技术的飞速发展&#xff0c;数据已成为企业最重要的资产之一。数据资产管理作为企业核心竞争力的关键组成部分&#xff0c;其发展趋势和技术创新受到了广泛关注。特别是在云计算、大数据、区块链等新技术不断涌现的背景下&#xff0c;数据资产管理面临着前所…

常用的JDK调优监控工具整理

JVM 调优首先要做的就是监控 JVM 的运行状态&#xff0c;这就需要用到各种官方和第三方的工具包了 一、 JDK 工具包 JDK 自带的 JVM 工具可以分为命令行工具和可视化工具 命令行工具 jps: JVM Process status tool&#xff1a;JVM进程状态工具&#xff0c;查看进程基本信息j…

阻塞IO、非阻塞IO、IO复用的区别 ?(非常详细)零基础入门到精通,收藏这一篇就够了

前言 在《Unix网络编程》一书中提到了五种IO模型&#xff0c;分别是&#xff1a;阻塞IO、非阻塞IO、IO复用、信号驱动IO以及异步IO。本篇文章主要介绍IO的基本概念以及阻塞IO、非阻塞IO、IO复用三种模型&#xff0c;供大家参考学习。 一、什么是IO 计算机视角理解IO: 对于计…

关闭kylin(麒麟)系统的安全认证(烦人的安全认证)

打开grub sudo vim /etc/default/grup修改安全认证选项 增加12行&#xff0c;把13行注释掉 保存更改, 然后执行下面的命令&#xff1a; sudo sync sudo reboot重启成功后&#xff0c;就关闭了安全认证了~~~~~。 总体来讲&#xff0c;kylin还是基于ubuntu的内核的&#xff0c;…

多号朋友圈统一管理,自动转发是什么体验?

拥有多个微信号的你&#xff0c;是不是也觉得手动管理和发布多个朋友圈可能会非常耗时&#xff1f; 今天&#xff0c;就分享一个神器给你&#xff0c;让你可以高效管理多个微信号的朋友圈&#xff0c;并实现自动转发。 首先&#xff0c;你需要在个微管理系统上登录所有的微信…

停止游戏中的循环扣血显示

停止游戏中循环扣血并显示的具体实现方式会依赖于你的代码结构和游戏的逻辑。通常情况下&#xff0c;你可以通过以下方式来实现停止循环扣血和显示&#xff1a; 1、问题背景 在使用 Python 代码为游戏开发一个生命值条时&#xff0c;遇到了一个问题。代码使用了循环来减少生命…

【博客718】时序数据库基石:LSM Tree(log-structured merge-tree)

时序数据库基石&#xff1a;LSM Tree(log-structured merge-tree) 1、为什么需要LSM Tree LSM被设计来提供比传统的B树更好的写操作吞吐量&#xff0c;通过消去随机的本地更新操作来达到这个目标&#xff0c;使得写入都是顺序写&#xff0c;而不是随机写。 那么为什么这是一个…

Eclipse 单步调试的时候报错,通过一些设置处理下。

先帖张图&#xff1a; 勾选不提醒。 1、通过Java Compiler&#xff0c;进行设置: 然后设置以后&#xff0c;进入调试&#xff0c;还是 报上面的错&#xff0c;有的小伙伴说是先去勾选&#xff0c;然后确认。 然后再选择&#xff0c;确认。 2、设置Jdk为自己安装的。 设置成功后…

积木搭建游戏-第13届蓝桥杯省赛Python真题精选

[导读]&#xff1a;超平老师的Scratch蓝桥杯真题解读系列在推出之后&#xff0c;受到了广大老师和家长的好评&#xff0c;非常感谢各位的认可和厚爱。作为回馈&#xff0c;超平老师计划推出《Python蓝桥杯真题解析100讲》&#xff0c;这是解读系列的第83讲。 积木搭建游戏&…

LaTeX 学习 第2节 数学结构

----用教授的方式学习 目录 2.1 上标与下标 2.2 上下画线与花括号 2.3 分式 2.4 根式 2.5 矩阵 ​​​​​​​LaTex安装包&#xff1a;https://download.csdn.net/download/weixin_38135241/89416392 LaTex- windows安装包&#xff1a;https://download.csdn.net/down…

TF-IDF算法:探究文本分析的关键技术

在自然语言处理(NLP)和信息检索领域,TF-IDF(Term Frequency-Inverse Document Frequency)算法是一种被广泛使用且极其重要的技术。它通过衡量单词在文档集中的重要性来帮助理解和处理文本数据。本文将详细探讨TF-IDF算法的原理、实现、应用及其在实际场景中的表现,并分析…

JVM 垃圾回收分配及算法

一、判断对象是否可以回收 垃圾收集器在做垃圾回收的时候&#xff0c;首先需要判定的就是哪些内存是需要被回收 的&#xff0c;哪些对象是「存活」的&#xff0c;是不可以被回收的&#xff1b;哪些对象已经「死掉」了&#xff0c;需 要被回收。 一般有两种方法来判断&#xff…