uni-app 实现日历组件

        实际开发场景中,涉及到用户签到数据需要展示日历及每天是否签到数据状态标识,下面为作者实际开发时使用的日历组件,其为去除掉实际业务代码后的通用代码。

前言

        1、使用组件使用为 uview 库

        2、时间格式化插件 dayjs

       

calendar日历组件

<template>
	<view class="calendar">
		<view class="calendar-title">
			<text>我的日历</text>
			<view class="close" @click="$emit('close')">
				<u-icon class="" name="close" size="44rpx"></u-icon>
			</view>
		</view>
		<view class="calendar-years">
			<u-icon class="" name="arrow-left" size="13px" @click="prevMonth"></u-icon>
			<view class="calendar-year">{{ year }}年{{ month }}月</view>
			<u-icon v-if="showNextMonth" name="arrow-right" size="13px" @click="nextMonth"></u-icon>
		</view>
		<view class="calendar-body">
			<view class="calendar-weekdays" v-if="showWeekdays">
				<view class="calendar-weekday" v-for="weekday in weekdays" :key="weekday">
					{{ weekday }}
				</view>
			</view>
			<view class="calendar-dates">
				<view class="calendar-date" v-for="(date, index) in dates" :key="index">
					<view class="calendar-date-null" v-if="!date"></view>
					<view class="calendar-date-item" v-else @click="itemHandle(date)">
						<view class="calendar-date-item-day">
							<text>{{isTodayText(date)}}</text>
						</view>
					</view>
				</view>
			</view>
		</view>
	</view>
</template>

<script>
	export default {
		name: "calendar",
		props: {
			// 月份日期列表
			datesd: {
				type: Array,
				default: () => {
					return []
				}
			},
			// 是否显示周标题
			showWeekdays: {
				type: Boolean,
				default: true
			},
			open: {
				type: Boolean,
				default: false
			}
		},
		data() {
			return {
				// 当前所处日期 年月日
				nowDate: this.$jy.formatDate(new Date(), 'YYYY-MM-DD'),
				// 当前所处年
				year: new Date().getFullYear(),
				// 当前所处月
				month: new Date().getMonth() + 1,
				weekdays: ["一", "二", "三", "四", "五", "六", "日"],
				showNextMonth: true, //是否显示查看下个月操作箭头,暂时只能看后一个月
			};
		},
		computed: {
			dates() {
				const firstDayOfMonth = new Date(this.year, this.month - 1, 1);
				const lastDayOfMonth = new Date(this.year, this.month, 0);
				const dates = [];
				for (let i = 0, len = this.datesd.length; i < len; i++) {
					dates.push(this.datesd[i]);
				}
				if (firstDayOfMonth.getDay() == 0) {
					// 第一行只有一天的情况
					for (let i = 1; i <= 6; i++) {
						dates.unshift(null);
					}
				} else {
					for (let i = 1; i < firstDayOfMonth.getDay(); i++) {
						dates.unshift(null);
					}
				}
				return dates;
			},
		},
		watch: {
			open: {
				handler(val) {
					if (val) {
						this.month = new Date().getMonth() + 1
					}
				},
				deep: true
			},
			month: {
				handler() {
					// 日期格式化获取当前月份
					const todayMonth = uni.$jy.formatDate(new Date(), 'M');
					// 日期格式化获取当前年
					const y = uni.$jy.formatDate(new Date(), 'YYYY')
					if (Number(todayMonth) == 12) {
						if (this.year > Number(y)) {
							this.showNextMonth = false
							return
						}
					}
					if (Number(y) < this.year) {
						this.showNextMonth = true
						return
					}
					if (Number(y) == this.year) {
						if (this.month < Number(todayMonth)) {
							this.showNextMonth = true
							return
						}
						let a = Math.abs(this.month - Number(todayMonth))
						if (a == 1) {
							this.showNextMonth = false
							return
						}
					}
					this.showNextMonth = true
					return
				},
			}
		},
		methods: {
			/* 上个月 */
			prevMonth() {
				if (this.month === 1) {
					this.year -= 1;
					this.month = 12;
				} else {
					this.month -= 1;
				}
				let callMonth = this.month >= 10 ? String(this.month) : '0' + String(this.month)
				let callBackDate = String(this.year) + "-" + callMonth
				this.$emit('prev', callBackDate)
			},
			/* 下个月 */
			nextMonth() {
				if (this.month === 12) {
					this.year += 1;
					this.month = 1;
				} else {
					this.month += 1;
				}
				let callMonth = this.month >= 10 ? String(this.month) : '0' + String(this.month)
				let callBackDate = String(this.year) + "-" + callMonth
				this.$emit("next", callBackDate)
			},
			/** 回显每日日期文本
			 * @param {Object} date 
			 */
			isTodayText(date) {
				if (date === this.nowDate) {
					return '今天'
				}
				return uni.$jy.formatDate(date, 'D')
			},
			/* 每日点击事件 */
			itemHandle(item) {
				this.$emit('item-cilck', item)
			},
		},
	};
</script>

<style scoped lang="scss">
	.calendar {
		padding: 35rpx;
		width: 624rpx;
		min-height: 705rpx;
		border-radius: 19rpx;
		background: #FFFFFF;
	}

	.calendar-title {
		padding-bottom: 25rpx;
		display: flex;
		justify-content: space-between;
		font-size: 28rpx;
		font-family: Source Han Sans CN;
		font-weight: 400;
		color: #000000;
		line-height: 28rpx;
		border-bottom: 2rpx solid #F5F5F5;

		.close {
			position: relative;
			width: 44rpx;
			height: 44rpx;

			&::before {
				position: absolute;
				left: -12rpx;
				top: -12rpx;
				right: -12rpx;
				bottom: -12rpx;
				content: " ";
			}

		}
	}

	.calendar-years {
		margin-top: 25rpx;
		margin-bottom: 20rpx;
		display: flex;
		justify-content: center;
		align-items: center;

		.calendar-year {
			margin: 0 40rpx;
			font-size: 28rpx;
			line-height: 28rpx;
			font-weight: 600;
		}
	}

	.calendar-body {
		padding: 0 4rpx;
		display: flex;
		flex-direction: column;
		font-size: 26rpx;
		font-family: DIN Pro;
		font-weight: 400;
		color: #000000;
		line-height: 26rpx;

		.calendar-weekdays {
			display: flex;

			.calendar-weekday {
				flex: 1;
				padding: 8rpx;
				text-align: center;
			}
		}

		.calendar-dates {
			display: flex;
			flex-wrap: wrap;


			.calendar-date {
				margin-bottom: 20rpx;
				width: calc(100% / 7);
				height: 80rpx;
				text-align: center;

				.calendar-date-item,
				.calendar-date-null {
					position: relative;
					margin: 0 auto;
					display: flex;
					flex-direction: column;
					justify-content: center;
					align-items: center;
					width: 59rpx;
					height: 100%;
					border-radius: 16rpx;

					.calendar-date-item-day {
						display: flex;
						align-items: flex-end;
						justify-content: center;
						height: 41rpx;
					}

				}
			}
		}
	}
</style>

日历组件中涉及到的时间格式化工具 js 方法,使用 day.js 轻量级日期格式化插件。

import dayjs from "dayjs" //轻量级日期格式化插件 ;

/** 时间日期格式化
 * @param {Object} time-时间信息
 * @param {Object} format-格式化样式
 * @return {String} 返回格式化后的时间字符串
 */
function formatDate(time, format) {
	if (!time) {
		return '';
	}
	return dayjs(time).format(format || "YYYY-MM-DD HH:mm:ss");
}

组件使用

<template>
	<view class="content">
		<button @click="openPopup">打开日历弹窗</button>

		<!-- 日历弹窗 -->
		<u-popup :show="calendarPopup" mode="center" round="9px">
			<calendar :datesd="datesd" :open="calendarPopup" @prev="getRili" @next="getRili" @close="calendarPopup=false;">
			</calendar>
		</u-popup>
	</view>
</template>

<script>
	import calendar from "../calendar/index.vue"
	export default {
		components: {
			calendar
		},
		data() {
			return {
				calendarPopup: false,
                //日历数据
				datesd: [],
			}
		},
		onLoad() {},
		methods: {
			openPopup() {
                // 模拟一个月的日期数据
				let total = 30
				for (let i = 1; i <= total; i++) {
					if (i < 10) {
						this.datesd.push(`2024-11-0${i}`)
					} else {
						this.datesd.push(`2024-11-${i}`)
					}
				}
                
                //弹窗打开
				this.calendarPopup = true
			},
            //获取上月/下月数据
			getRili() {

			}
		}
	}
</script>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值