<uniapp><日期组件>基于uniapp,编写一个自定义的日期组件

前言

本专栏是关于uniapp的相关介绍,如果你对uniapp感兴趣,不妨来看看。

环境配置

系统:windows10

平台:HBuilderX4.76

语言:vue、javascript

库:uni

概述

本文是基于uniapp,编写的自定义日期选择器组件,大致效果如下:

1、组件简介

这是一个日期选择器,即可以选择年、月、日的组件,所以,组件的功能是很简单的,组件的效果就是如上面的效果图所示,按照年月日基本划分为三个区域。

一般的日期组件,都是不列出详细年份与月份的,只会显示月份下面详细日期。如果要修改年份或者月份,通常是再次点击,在弹出的窗口滑动或者滚动选择。 比如uni提供的日期选择器:

当然,以上举例不涉及孰优孰劣,只涉及个人喜好。

我个人的想法是,如果一个要选择出生年月日的组件,为什么不直接让用户能够在一个页面选择呢?而不是还需要在二次界面上去滚动选择。

至少像月份,就12个月,是完全可以列出来的。

而年份也是可以的,但是对于不同人的出生年份,初始化时肯定无法兼容,所以增加了一个输入框,可以直接输入需要的年份,或者输入一个接近的年份,输入完成后,年份列表会显示前后10年(范围值可以设置,默认是10)的所有年份。

2、组件实现

如果你也喜欢这样的日期选择界面,可以接着往下看,下面将介绍一下组件的实现。

我们使用HBuilder新建一个项目,然后添加一个component文件夹,在文件夹下添加一个页面:myDatePicker.vue:

我们主要的代码都是写在这个文件中。

组件的结构,是两个部分,一个是固定显示部分,一个是弹出窗口。 固定显示部分就是我们在其他页面调用组件时显示所有,点击此部分,就会弹出日期选择界面。

所以,弹出界面在初始化时,是隐藏的。点击固定显示部分,则弹出选择界面,如果点击组件外部的任何空白部分,则弹出界面隐藏。

上面所描述的,也都是最基本的功能了。

我们按照年、月、日三个部分来分别说一下实现。

1、年份

如图,我们自定义的组件中,年份是按照列表来显示的,它是当前选定年份为中心,前、后各显示10年的范围,其中10年是一个参数range,可以设置,也可以使用默认(为10)。

如上图,我们将range定义为属性,然后我们添加一个年份列表,使用计算属性:

js 复制代码
const yearList = computed(()=>{
		const centerYear = selectedYear.value;
		let start =centerYear - props.range;
		let end = centerYear + props.range;
		let tempCenterYear = centerYear;
		//对起始年份进行判断
		if(start < 1900){
			tempCenterYear = 1900 + props.range;
			start = 1900;
			end = tempCenterYear + props.range;
		}
		//生成年份列表
		const list =Array.from(
			{length:end - start + 1},
			(_,i)=>start + i
		); 
		if(!list.includes(currentYear.value)){
			list.push(currentYear.value)
		}
		return list;
	});
2、月份

月份不需要计算,固定为12个月即可。

3、日

每个月的日期,则需要根据月份进行计算,比如2月一般只有28天,但是需要计算年份是否是闰年,如果是闰年,则为29天。至于大小月之分,则比较简单,固定值即可。

js 复制代码
const daysInMonth = computed(()=>{
		const year = tempselectedYear.value;
		const mon = tempselectedMonth.value;
		/* const mon = selectedMonth.value; */
		if(mon === 2) {
			//判断年份是否是闰年
			const isLeapYear = (year % 4 === 0 && year % 100 !==0) || (year % 400 === 0);
			return isLeapYear ? 29:28;
		};
		if([4,6,9,11].includes(mon))return 30;
		return 31;
	});
4、星期对应

通常,一个日期选择器都会将每个月的每一天对应星期几都列出来,如下:

所以,每个月的天数显示,都不是只显示当月的天数,有时候会包含上个月末尾几天以及下个月开头几天。

这取决于所选择的月份的1号是星期几,比如,1号是星期三,如果星期的排布从左到右是周日到周六,那么应该将上个月的最后几天填充进来,以便于日期显示有一种连续感。

所以,这里就涉及到一个计算,即,当选择某个月份后,怎样判断上个月的末尾显示几天,下个月的开头显示几天,而这又取决于当月1号是星期几。 所以,我们可以添加两个计算属性:

js 复制代码
//计算上个月需要补几天
	const prevMonthDays = computed(()=>{
		const prevYear = tempselectedMonth.value === 1 ? tempselectedYear.value - 1 : tempselectedYear.value;
		const prevMonth = tempselectedMonth.value === 1 ? 12 : tempselectedMonth.value - 1;
		//获取上个月的最后一天是几号
		//console.log(`${prevYear}--${prevMonth}`);
		const prevMonthLastDay = new Date(prevYear,prevMonth,0).getDate();
		//console.log(prevMonthLastDay);
		const cur_weekday = new Date(tempselectedYear.value,tempselectedMonth.value-1,1).getDay();
		//console.log(cur_weekday)
		const days = [];
		for(let i = cur_weekday - 1;i>=0;i--){
			days.push(
				{
					day:prevMonthLastDay - i,
					month:prevMonth,
					year:prevYear,
					type:'prev'
				}
			);
		};
		return days;
	});
js 复制代码
//计算下个月开头几天
	const nextMonthDays = computed(()=>{
		const nextMonthYear = tempselectedMonth.value === 12 ? tempselectedYear.value + 1 : tempselectedYear.value;
		const nextMonth = tempselectedMonth.value === 12 ? 1 : tempselectedMonth.value + 1;
		const total = 42;
		const daystoshow = total - (prevMonthDays.value.length + daysInMonth.value);
		const days = [];
		for(let i=1;i<=daystoshow;i++){
			days.push({
				day:i,
				month:nextMonth,
				year:nextMonthYear,
				type:'next'
			});
		};
		return days;
	});

如上,其中最重要的是前一个月末尾几天的计算,这个计算出来,下一个月的天数就好计算了。因为我们为了方便,整个天数显示界面是设置了一个总数即42天,也就是6个星期。其中包含了当月所有天数,上个月末尾天数,以及下个月开头天数。

最后,我们把所有天数汇总:

js 复制代码
	//合并日期
	const allDays = computed(()=>{
		let alldays = [];
		alldays =  [
			...prevMonthDays.value,
			...Array.from({length:daysInMonth.value},(_,i)=>({
				day:i+1,
				month:tempselectedMonth.value,
				year:selectedYear.value,
				type:'select'
			})),
			...nextMonthDays.value
		];
		return alldays;
	});

然后我们渲染天数使用allDays变量即可:

html 复制代码
<view class="popup-day">
					<view
						v-for="dd in allDays"
						:key="dd"
						class="popup-day1"
						:class="[
							{ 'active':tempselectedDay === dd.day && dd.type === 'select' },
							{'current-day':dd.day === currentDay && dd.type !== 'prev' && dd.type !== 'next' && tempselectedDay !== dd.day},
							{'noncurrent-day':dd.type === 'prev' || dd.type === 'next'}
							]"
						@click="dd.type === 'select' && day1Click(dd.day)">
						<text>{{dd.day}}</text>
					</view>
				</view>

渲染效果如下图:

如图,样式上,只有当月天数可以选择,前月和后月天数只能看,不能选,因此为灰色。而当月天数,如果选中,则背景色为蓝色。而对于今日日期,如果选中,则也是蓝色背景,如果选择了其他天数,则今天会显示一个虚线橙色外框,以提示用户。

上面就是大致的思路,最后完成的效果演示:

相关推荐
王六岁3 小时前
Vue 3 表单验证组合式 API,提供类似 Ant Design Vue Form 的强大表单验证功能
前端·vue.js
lypzcgf3 小时前
Coze源码分析-资源库-创建提示词-前端源码
前端·人工智能·typescript·系统架构·开源软件·react·安全架构
fury_1233 小时前
vue3:el-date-picker三十天改成第二十九天的23:59:59
前端·javascript·vue.js
小周同学@3 小时前
DOM常见的操作有哪些?
前端·javascript
文心快码BaiduComate3 小时前
5句话让文心快码实现一个大模型MBTI测试器
前端·后端·llm
橙某人4 小时前
💫分享一个CSS技巧:用径向渐变实现弯曲框缺口效果
前端·css
颜酱4 小时前
基于 Ant Design 的配置化表单开发指南
前端·javascript·react.js
anyup4 小时前
uni-app 项目创建方式有哪些,看这一篇就够了!
前端·vue.js·uni-app
ERP老兵-冷溪虎山4 小时前
Python/JS/Go/Java同步学习(第二篇)四语言数据基本类型对照表: 老板让我统一系统数据类型?(附源码/截图/参数表/老板沉默术)
java·javascript·python·golang·基本数据类型·多语言编程·中医编程