uniapp 封装时间选择器组件

背景

项目使用的ui框架为uView UI,因项目功能需求需要实现时间选择器可以选择秒,但是uview不支持,所以自行解决。

最终版是基于uview UI的时间组件代码做修改,实现功能。

基于uniapp picker-view 组件封装(功能不完善)

最后实现功能如图:

插曲:vue 自定义 v-model 的实现查看我的另一篇文章:

UI组件二次封装之自定义 v-model

HTML

<template>
	<u-popup :show="show && !disabled" mode="bottom" :round="round">
		<view class="time-content">
			<view class="header-top">
				<slot name="header">
					<view class="cancel" @click="cancel">{
   
   {cancelText}}</view>
					<view class="title">{
   
   {title}}</view>
					<view class="confirm" @click="confirm">{
   
   {confirmText}}</view>
				</slot>
			</view>
			<view class="time-wrapper">
				<picker-view
					:value="pickerValue" 
					indicator-class="picker-box"
					:indicator-style="indicatorStyle"
					@change="bindChange"
				>
					<picker-view-column v-for="(item,index) in innerColumns" :key="index">
					    <view class="item" v-for="(item1,index1) in item.values" :key="index1">
							{
   
   {item1}}{
   
   {item.label}}
						</view>
					</picker-view-column>
				</picker-view>
			</view>
		</view>
	</u-popup>
</template>

JS

<script>
	export default {
		name: 'GDatepicker',
		/**
		 * 插槽
		 * header  自定义头部样式
		 */
		props:{
			value:{
				type: [String,Number],
				default:''
			},
			show: {
				type:[Boolean,String],
				default:false
			},
			cancelText: {
				type:String,
				default:'取消'
			},
			confirmText: {
				type:String,
				default:'确定'
			},
			title: {
				type:String,
				default:'时间选择'
			},
			/**
			 * 是否格式化时间
			 * format 格式同 uView timeFormat API,如:"yyyy-mm-dd"
			 * 格式可以自由搭配: 年为"yyyy",月为"mm",日为"dd",时为"hh",分为"MM",秒为"ss",
			 * 注意分为 大写M
			  */
			format: {
				type:String,
				default:''
			},
			// 是否转换成json格式数据 如:2020-01-01T19:19:20.253Z
			formatToJson: {
				type: Boolean,
				default: false
			},
			/**
			 * 时间模式(选择器可选时间格式)(如果mode为date,则format不应包含时分秒格式)
			 * datetime  全时间:年月日时分秒
			 * date  只包含年月日
			 */
			mode: {
				type: String,
				default: 'datetime'
			},
			// 可选的最大时间 时间戳毫秒 默认后十年
			maxDate: {
				type: [String, Number],
				default: new Date(new Date().getFullYear() + 10, 0, 1).getTime(),
			},
			// 可选的最小时间 时间戳毫秒 默认前十年
			minDate: {
				type: [String, Number],
				default: new Date(new Date().getFullYear() - 10, 0, 1).getTime(),
			},
			minMonth: {
				type: [String, Number],
				default: 1
			},
			maxMonth: {
				type: [String, Number],
				default: 12
			},
			minDay: {
				type: [String, Number],
				default: 1
			},
			maxDay: {
				type: [String, Number],
				default: 31
			},
			// 弹窗圆角值
			round: {
				type: [String, Number],
				default:0
			},
			disabled:{
				type:Boolean,
				default:false
			}
		},
        model: {
			prop: 'value',
			event: 'input'
		},
		data() {
			return {
				year: 2022,
				month: 0,
				day: 0,
				hour: 0,
				minute: 0,
				second: 0,
				pickerValue: [], // picker-view绑定值
				innerColumns: [],
				indicatorStyle: `color: red;!important`
			}
		},
		watch:{
			show(val) { 
				if(val) {
                    this.initData()
					if(this.value) {
						this.setData(this.value)
					} else {
						this.setData()
					}
				}
			}
		},
		// mounted() {
			// this.initData()
		// },
		methods: {
			initData() {
				const startYear = new Date(Number(this.minDate)).getFullYear()
				const endYear = new Date(Number(this.maxDate)).getFullYear()
				let result = [
					{
						type: 'year',
						label: '年',
						range: [startYear, endYear]
					},
					{
						type: 'month',
						label: '月',
						range: [this.minMonth, this.maxMonth]
					},
					{
						type: 'day',
						label: '日',
						range: [this.minDay, this.maxDay]
					},
					{
						type: 'hour',
						label: '时',
						range: [0,23]
					},
					{
						type: 'minute',
						label: '分',
						range: [0, 59]
					},
					{
						type: 'secode',
						label: '秒',
						range: [0, 59]
					}
				]
				this.innerColumns = result.map(({ type, label, range }) => {
					const num = range[1] - range[0] + 1;
					let values = this.getColumnTimes(num, (index) => {
					    let value = range[0] + index
					    value = type === 'year' ? `${value}` : this.padZero(value)
					    return value
					})
					return { type, label, values }
				})
				if(this.mode === "date") {
					this.innerColumns.splice(3,3)
				}
			},
			bindChange (e) {
			    const val = e.detail.value;
				const date = new Date();
				this.year = this.getCurrCol(0)[val[0]] || date.getFullYear()
				this.month = this.getCurrCol(1)[val[1]] ||date.getMonth() + 1;
				this.day = this.getCurrCol(2)[val[2]] || date.getDate()
				this.hour = this.getCurrCol(3)[val[3]] || date.getHours();
				this.minute = this.getCurrCol(4)[val[4]] || date.getMinutes();
				this.second = this.getCurrCol(5)[val[5]] || date.getSeconds();
				/* // change事件 需要启用取消注释
				const currentTime = new Date(this.year,this.month - 1,this.day,this.hour,this.minute,this.second).getTime()
				if(this.format) {
					this.$emit('change',uni.$u.timeFormat(currentTime,this.format))
				} else {
					this.$emit('change',currentTime)
				} */
			},
			getCurrCol(index) {
				if(!this.innerColumns[index]) {
					return []
				}
				return this.innerColumns[index].values
			},
			cancel() {
				this.$emit('cancel')
				this.$emit('update:show',false)
			},
			confirm() {
				const str = `${this.year}/${this.month}/${this.day} ${this.hour}:${this.minute}:${this.second}`
				const time = new Date(str).getTime()
				this.$emit('confirm',this.formatDate(time))
                this.$emit('input', this.formatDate(time));
			},
			// set data
			setData(value) {
				let date;
				if(value) {
					const n = isNaN(value) ? value : Number(value)
					date = new Date(n)
				} else {
					date = new Date()
				}
				const startYear = new Date(Number(this.minDate)).getFullYear()
				this.year = date.getFullYear()
				// 绑定时间小于当前时间列表的开始时间则取第一项
				const yearColumnIndex = this.year > startYear ? this.year - startYear : 0
				this.day = date.getDate()
				this.month = date.getMonth() + 1
				this.hour = date.getHours()
				this.minute = date.getMinutes()
				this.second = date.getSeconds()
				// pickerValue数组中的项依次表示 picker-view 内的 picker-view-column 选择的第几项
				this.pickerValue = [yearColumnIndex,this.month - 1,this.day - 1,this.hour,this.minute,this.second]
				this.$nextTick(() => {
					if(this.mode === "date") {
						this.pickerValue.splice(3,3)
					}
				})
			},
			formatDate(time) {
				if(this.format) {
					return uni.$u.timeFormat(time,this.format)
				} else if(this.formatToJson) {
					return new Date(time).toJSON()
				} else {
					return time
				}
			},
			// 设置列数据
			getColumnTimes(n, iteratee) {
			    let index = -1
			    const result = Array(n < 0 ? 0 : n)
			    while (++index < n) {
			        result[index] = iteratee(index)
			    }
			    return result
			},
			// 字符串转换
			padZero(num, targetLength = 2) {
			    let str = `${num}`
			    while (str.length < targetLength) {
			        str = `0${str}`
			    }
			    return str
			}
		}
	}
</script>

CSS

<style lang="scss" scoped>
	picker-view {
	  width: 100%;
		height: 100%;
	}
	
	.time-content {
		height: 280px;
		.header-top {
			height: 44px;
			line-height: 44px;
			display: flex;
			padding: 0 16px;
			font-size: 15px;
			border-bottom: 1px solid #EEEEEE;
			overflow: hidden;
			.cancel {
				color: #999999;
			}
			.title {
				flex: 1;
				text-align: center;
				color: #666666;
			}
			.confirm {
				color: #27B57D;
			}
		}
		.time-wrapper {
			height: calc(100% - 44px);
			box-sizing: border-box;
			text-align: center;
			.picker-box {
				height: 44px;
				font-size: 18px!important;
				font-weight: 800!important;
				color: #333333!important;
			}
			.item {
			    line-height: 44px;
			    text-align: center;
			}
		}
	}
</style>

使用

<template>
    <g-time-picker
            :show="show"
			:title="'选择装货时间'"
			v-model="value"
			@cancel="cancelFn"
			@confirm="confirmFn"
			:format="'yyyy-mm-dd hh:MM:ss'"
			:minDate="'1587524800000'"
			:maxDate="'1786778555000'"
        ></g-time-picker>
</template>

<script>
	import GTimePicker from "@/components/Time/index.vue"
	export default {
		name:'timePicker-demo',
		components:{GTimePicker},
		data() {
			return {
				show: false,
                // value: "" ,
                value: "2024-11-11 11:11:11" ,
				inputValue: ''
			}
		},
		methods: {
			btnClick(e) {
				this.show = true;
			},
			cancelFn() {
				console.log(this.value,'cancel');
				this.show = false;
			},
			confirmFn(e) {
				console.log(this.value,'confirm');
				// this.inputValue = this.value
				this.show = false;
			}
		}
	}
</script>

基于uView UI的时间选择器代码修改

 项目使用uview  ui 的方式为本地安装,时间组件中使用到了其他的uview ui 基础组件,使用请自行处理,全局安装,或者按需引入都可以,下面是我基于uview 时间选择器源码修改后的代码:

百度网盘 请输入提取码

提取码:i3ng

猜你喜欢

转载自blog.csdn.net/lwx931449660/article/details/122354323
今日推荐