效果图:
代码
<script setup name="PopupAllPicker">
const emit = defineEmits(['update:modelValue', 'confirm']);
const attrs = useAttrs();
const props = defineProps({
modelValue: {
type: Boolean,
default: false
},
values: {
type: String,
default: ''
},
title: {
type: String,
default: '请选择时间'
},
valueFormat: {
type: String,
default: 'YYYY-MM-DD HH:mm:ss'
}
});
// 是否显示弹出层
const columns = ref([]);
const Mdays = ref('');
const Dindex = ref(null);
const picker = ref(null);
// 获取某年某月多少天
function getCountDays(year, month) {
const day = new Date(year, month, 0);
return day.getDate();
}
// 获取年月日时分秒列信息
function getColumns() {
const strTime = props.values;
let vModuleDate;
if (props.values !== '') {
vModuleDate = new Date(strTime.replace(/-/g, '/'));
} else {
vModuleDate = new Date(); // 没有传入时间则默认当前时刻
}
const Y = vModuleDate.getFullYear();
const M = vModuleDate.getMonth();
const D = vModuleDate.getDate();
const h = vModuleDate.getHours();
const m = vModuleDate.getMinutes();
const s = vModuleDate.getSeconds();
const year = {}; // 获取前后十年数组
year.values = [];
const CurrentDay = new Date().getFullYear();
for (let i = CurrentDay - 4; i < CurrentDay + 1; i += 1) {
year.values.push(i);
}
year.defaultIndex = year.values.indexOf(Y);
const month = {};
// 获取12月数组
month.defaultIndex = M;
month.values = Object.keys([...Array(13)]).map((item) => {
if (+item + 1 <= 10) {
return `0${item}`;
}
if (+item + 1 === 11) {
return `${item}`;
}
return (+item + 0).toString();
});
month.values.splice(0, 1);
const days = getCountDays(Y, Mdays.value === '' ? M + 1 : Mdays.value);
const day = {}; // 创建当月天数数组
day.defaultIndex = Dindex.value === null ? D - 1 : Dindex.value;
day.values = Object.keys([...Array(days + 1)]).map((item) => {
if (+item + 1 <= 10) {
return `0${item}`;
}
if (+item + 1 === 11) {
return `${item}`;
}
return (+item + 0).toString();
});
day.values.splice(0, 1);
const hour = {}; // 创建小时数组
hour.defaultIndex = h;
hour.values = Object.keys([...Array(24)]).map((item) => {
if (+item + 1 <= 10) {
return `0${item}`;
}
if (+item + 1 === 11) {
return `${item}`;
}
return (+item + 0).toString();
});
const mi = {}; // 创建分钟数组
mi.defaultIndex = m;
mi.values = Object.keys([...Array(60)]).map((item) => {
if (+item + 1 <= 10) {
return `0${item}`;
}
if (+item + 1 === 11) {
return `${item}`;
}
return (+item + 0).toString();
});
const ss = {}; // 创建秒数数组
ss.defaultIndex = s;
ss.values = Object.keys([...Array(60)]).map((item) => {
if (+item + 1 <= 10) {
return `0${item}`;
}
if (+item + 1 === 11) {
return `${item}`;
}
return (+item + 0).toString();
});
// 设置默认选项当前年
if (props.valueFormat.includes('YYYY')) {
columns.value.push(year);
}
if (props.valueFormat.includes('MM')) {
columns.value.push(month); // 获取当月的天数
}
if (props.valueFormat.includes('DD')) {
columns.value.push(day);
}
if (props.valueFormat.includes('HH')) {
columns.value.push(hour);
}
if (props.valueFormat.includes('mm')) {
columns.value.push(mi);
}
if (props.valueFormat.includes('ss')) {
columns.value.push(ss);
}
}
function onChange(values) {
// a为所有列备选项值的数组
const days = getCountDays(values[0], values[1]);
const newDays = {};
newDays.values = Object.keys([...Array(days + 1)]).map((item) => {
if (+item + 1 <= 10) {
return `0${item}`;
}
if (+item + 1 === 11) {
return `${item}`;
}
return (+item + 0).toString();
});
newDays.values.splice(0, 1);
// 设置第三列的值
picker.value.setColumnValue(2, newDays.values);
// 设置第三列索引
picker.value.setColumnIndex(2, values[2] - 1);
}
// 关闭弹框
function onCancel() {
Mdays.value = '';
Dindex.value = null;
emit('update:modelValue', false);
}
// 时间选择器确定
function onConfirm(val) {
let endVal = '';
for (let i = 0; i < columns.value.length; i += 1) {
endVal += val[i];
if (i === 2) {
endVal += ' ';
} else if (i >= 3 && i <= 5) {
endVal += ':';
} else if (i < columns.value.length - 1) {
endVal += '-';
}
}
// 判断最后一个字符是否是分隔符
if (endVal.endsWith('-') || endVal.endsWith(':')) {
endVal = endVal.slice(0, -1); // 删除最后一个字符
}
emit('update:modelValue', false);
emit('confirm', endVal);
}
watch(
() => props.modelValue,
(val) => {
if (!val) emit('update:modelValue');
columns.value = [];
getColumns();
}
);
watch(
() => props.values,
(val) => {
if (val === '') {
Mdays.value = '';
Dindex.value = null;
}
}
);
</script>
<template>
<!-- 弹出层 -->
<van-popup :show="modelValue" round position="bottom" teleport="body" class="!rounded-t-[6px]" @close="onCancel">
<!-- 时间选择 -->
<van-picker
v-bind="attrs"
ref="picker"
show-toolbar
:title="title"
:columns="columns"
@change="onChange"
@cancel="onCancel"
@confirm="onConfirm"
/>
</van-popup>
</template>
<style lang="less" scoped></style>
使用
<script setup>
import dayjs from 'dayjs';
import PopupAllPicker from '../components/PopupAllPicker.vue';
const data = reactive({
popupCode: '',
dateType: 'date',
dateFormatter: 'YYYY-MM-DD',
datePicker: false,
pickerDate: '' // 当前时间选择器的时间
});
const form = reactive({
...,
})
// 选择器默认范围(当前时间前后2年)
const minDate = dayjs().subtract(2, 'year').$d;
const maxDate = dayjs().subtract(-1, 'year').$d;
// 确认时间
function onConfirmPicker(val) {
form[data.popupCode] = val;
}
</script>
<template>
...
<!-- 时间选择器 -->
<PopupAllPicker
v-model="data.datePicker"
ref="popup"
:values="data.pickerDate"
:min-date="minDate"
:max-date="maxDate"
:valueFormat="data.dateFormatter"
@confirm="onConfirmPicker"
/>
</template>