背景
项目使用的ui框架为uView UI,因项目功能需求需要实现时间选择器可以选择秒,但是uview不支持,所以自行解决。
最终版是基于uview UI的时间组件代码做修改,实现功能。
基于uniapp picker-view 组件封装(功能不完善)
最后实现功能如图:
插曲:vue 自定义 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