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>
相关推荐
Mango0000006 分钟前
香港站群服务器有助于提升网站在搜索引擎中的排名
运维·服务器·搜索引擎
嚯——哈哈8 分钟前
筑起数字堡垒:解析AWS高防盾(Shield)的全面防护能力
服务器·微服务·云计算·aws
humors22113 分钟前
阿里云ECS服务器监控报警配置
运维·服务器·安全·阿里云·云计算
杨江14 分钟前
ThingsBoard安装测试
服务器·数据库
明月清风徐徐24 分钟前
Vue实训---2-路由搭建
前端·javascript·vue.js
王解33 分钟前
速度革命:esbuild如何改变前端构建游戏 (1)
前端·vite·esbuild
葡萄城技术团队41 分钟前
使用 前端技术 创建 QR 码生成器 API1
前端
DN金猿43 分钟前
Vue移动端网页(H5)预览pdf文件(pdfh5和vue-pdf)(很详细)
前端·vue.js·pdf
鸽鸽程序猿1 小时前
【前端】javaScript
开发语言·前端·javascript
小林熬夜学编程1 小时前
【Linux系统编程】第五十弹---构建高效单例模式线程池、详解线程安全与可重入性、解析死锁与避免策略,以及STL与智能指针的线程安全性探究
linux·运维·服务器·c语言·c++·安全·单例模式