uni-app yrkDataPicker 日期和时间选择控件

uni-app 选择日期时间控件有 2 月份有 31 天的问题,一直没有修复,uni-calendar 苹果有选择年份和月份后无法显示问题。自己写了一个,只支持 H5 和微信小程序,其他没有试过。

复制代码
<template>
	<view class="yrk-data-picker">
		<uni-popup ref="pickerView" type="bottom" style="z-index: 9999999;">
			<view class="popup-view">
				<view class="popup-view-header">
					<view class="popup-view-cancel" @click="pickerCancel">取消</view>
					<view class="popup-view-confirm" @click="pickerConfirm">完成</view>
				</view>
				<picker-view v-if="visible" :indicator-style="indicatorStyle" :value="values" @change="bindChange" class="picker-view">
					<picker-view-column :style="dateStyle">
					    <view class="item" v-for="(item,index) in years" :key="index">{{formatTime(item)}}{{labels[0]}}</view>
					</picker-view-column>
					<picker-view-column  :style="dateStyle">
					    <view class="item" v-for="(item,index) in months" :key="index">{{formatTime(item)}}{{labels[1]}}</view>
					</picker-view-column>
					<picker-view-column  :style="dateStyle">
					    <view class="item" v-for="(item,index) in days" :key="index">{{formatTime(item)}}{{labels[2]}}</view>
					</picker-view-column>
					<picker-view-column :style="timeStyle">
					    <view class="item" v-for="(item,index) in hours" :key="index">{{formatTime(item)}}{{labels[3]}}</view>
					</picker-view-column>
					<picker-view-column :style="timeStyle">
					    <view class="item" v-for="(item,index) in minutes" :key="index">{{formatTime(item)}}{{labels[4]}}</view>
					</picker-view-column>
				</picker-view>
			</view>
		</uni-popup>
	</view>
</template>

<script>
	const da = new Date()
	/**
	 * yrkDataPicker 日期和时间选择控件
	 * @description 日期和时间选择控件 
	 * @copyright https://my.oschina.net/lovelong1/
	 * @property {Number} startYear 年份开始日期,默认1900
	 * @property {Number} endYear 年份结束日期 默认当前年份
	 * @property {String} mode = ['date','time','datetime'] 选择模式,日期,时间,日期时间,不包含秒针。
	 * @property {String} value 默认日期 格式,'1900-01-01 01:01:01' 默认当前,目前只支持全
	 * @event {Function} change 控件更换 参数 event 参考 picker-view change
	 * @event {Function} cancel 选择取消按钮 
	 * @event {Function} confirm 选择确认按钮 参数 格式化日期 Date数据
	 * @example <yrk-data-picker ref="pickerView" mode="time" value="1981-05-01 23:01:01" @confirm="pickerConfirm"></yrk-data-picker>
	 * 显示控件 this.$refs.pickerView.open('bottom');
	 * 关闭控件 this.$refs.pickerView.close();
	 * pickerConfirm(dateStr,da){ console.log(dataStr,da); }
	 */	
	export default {
		name:'yrkDataPicker',
		props: {
			startYear:	{ type:	Number, default:	1900 },
			endYear:	{ type:	Number, default:	da.getFullYear() },
			
			mode: 		{ type: String,	default: 	'time'	},
			value:		{ type: String,	default: 	null },
			
		},
		computed: {
			// 解决微信不显示问题。
			dateStyle() { return this.getStyle(['date','datetime']) },
			timeStyle() { return this.getStyle(['time','datetime']) }
		},
		watch: {
			mode:{
				immediate:true,
				handler(newValue, oldValue){this.init()}
			},
			value:{
				immediate:true,
				handler(newValue, oldValue){this.init()}
			}
		},
		data() {
			return {
				visible: true,
				tempvalues:[],//临时保存数据
				values:[],
				defaults:[
					{start:1900,end:da.getFullYear()},
					{start:1,end:12},
					{start:1,end:31},
					{start:0,end:23},
					{start:0,end:59}
				],
				labels:['年','月','日','点','分'],
				keys:['years','months','days','hours','minutes'],
				years:[],
				months :[],
				days :[],
				hours:[],
				minutes:[],
				indicatorStyle: ``,
			}
		},
		created() {
			this.defaults[0]={start:this.startYear,end:this.endYear};
			this.defaults.forEach((item,index)=>{
				for(let i = item.start;i<=item.end;i++){
					this[this.keys[index]].push(i);
				}
			})
		},
		methods: {
			getStyle(modes){
				const isShow = modes.includes(this.mode);
				return `flex:${isShow?1:0};width:${isShow?'auto':'0px'};`
			},
			init(){
				this.$nextTick(()=>{
					let year = da.getFullYear();
					let month = da.getMonth();
					let day = da.getDate();
					let hour = da.getHours();
					let minute = da.getMinutes();
					if(this.value){
						const val = this.parse(this.value);
						year = val.getFullYear();
						month = val.getMonth();
						day = val.getDate();
						hour = val.getHours();
						minute = val.getMinutes();
					}
					year = year - this.startYear;
					this.values = [0, 0, 0, 0, 0];
					setTimeout(()=>{
						this.values = [year, month, day-1,hour,minute];
					},0)
					this.upDays(year, month);
				})
			},
			parse: function(str) {
				var a = str.split(/[^0-9]/);
				return new Date(a[0], a[1] - 1, a[2], a[3], a[4], a[5]);
			},
			open(e){
				this.$refs.pickerView.open(e);
			},
			close(){
				this.$refs.pickerView.close();
				this.$emit('close')
			},
			pickerCancel() {
				this.$refs.pickerView.close();
				this.$emit('cancel')
			},
			formatTime(t){
				return (t<10?`0`:'')+t
			},
			pickerConfirm() {
				this.values = this.tempvalues;
				let year = this.formatTime(this.years[this.values[0]]);
				let month = this.formatTime(this.months[this.values[1]]) ;
				let day = this.formatTime(this.days[this.values[2]]) ;
				let hour = this.formatTime(this.hours[this.values[3]]);
				let minute = this.formatTime(this.minutes[this.values[4]]) ;
				let value = `${year}-${month}-${day} ${hour}:${minute}:00`
				if(this.mode==='date'){
					value = `${year}-${month}-${day}`
				}else if(this.mode==='time'){
					 value = `${hour}:${minute}`
				}
				this.$refs.pickerView.close();
				// console.log(value ,new Date(year,month-1,day,hour,minute,0))
				this.$emit('confirm', value ,new Date(year,month-1,day,hour,minute,0))
			},
			bindChange(e){
				// console.log(e);
				if(this.values[1] != e.detail.value[1]){
					const year = e.detail.value[0]+this.startYear;
					const month = e.detail.value[1]+1;
					this.upDays(year, month);
				}
				this.tempvalues = e.detail.value;
				this.$emit('change', e)
			},
			upDays(year,month){
				const monthDays = this.getMonthDaysByYearMonth(year,month);
				this.days = [];
				for (let i = 1; i <= monthDays; i++) this.days.push(i);
			},
			getMonthDaysByDate(da){
				return 	this.getMonthDaysByYearMonth(da.getFullYear(), da.getMonth);
			},
			getMonthDaysByYearMonth(year=1900,month=0){
				return 	new Date(year, month,0).getDate();
			}
		}
	}
</script>

<style lang="scss">
	.popup-view {
		background-color: #FFFFFF;
		.popup-view-header {
			display: flex;
			flex-direction: row;
			justify-content: space-between;
			align-items: center;
			border-bottom: 1px solid #F5F5F5;
			.popup-view-cancel,.popup-view-confirm {
				box-sizing: border-box;
				padding: 0 28rpx;
				font-size: 34rpx;
				line-height: 90rpx;
			}
			.popup-view-cancel{
				color: #888888;
			}
			.popup-view-confirm{
				color: #007aff;
			}
		}
		.picker-view {
			height: 476rpx;
			margin-top: 20rpx;
			.item{
				text-align: center;
				display: flex;
				flex-direction: column;
				align-items: center;
				justify-content: center;
			}

		}
		picker-view-column{
			// display: flex;
		}
	}
</style>
相关推荐
崔庆才丨静觅11 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby606112 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了12 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅12 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅12 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
七夜zippoe13 小时前
CANN Runtime任务描述序列化与持久化源码深度解码
大数据·运维·服务器·cann
盟接之桥13 小时前
盟接之桥说制造:引流品 × 利润品,全球电商平台高效产品组合策略(供讨论)
大数据·linux·服务器·网络·人工智能·制造
崔庆才丨静觅13 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment13 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅13 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端