Files
element-plus/packages/components/time-select/src/time-select.vue
2025-09-21 10:03:35 +08:00

148 lines
3.8 KiB
Vue

<template>
<el-select
ref="select"
:model-value="value"
:disabled="_disabled"
:clearable="clearable"
:clear-icon="clearIcon"
:size="size"
:effect="effect"
:placeholder="placeholder"
default-first-option
:filterable="editable"
:empty-values="emptyValues"
:value-on-clear="valueOnClear"
:popper-class="popperClass"
:popper-style="popperStyle"
@update:model-value="(event) => $emit(UPDATE_MODEL_EVENT, event)"
@change="(event) => $emit(CHANGE_EVENT, event)"
@blur="(event) => $emit('blur', event)"
@focus="(event) => $emit('focus', event)"
@clear="() => $emit('clear')"
>
<el-option
v-for="item in items"
:key="item.value"
:label="item.value"
:value="item.value"
:disabled="item.disabled"
/>
<template #prefix>
<el-icon v-if="prefixIcon" :class="nsInput.e('prefix-icon')">
<component :is="prefixIcon" />
</el-icon>
</template>
</el-select>
</template>
<script lang="ts" setup>
import { computed, ref } from 'vue'
import dayjs from 'dayjs'
import customParseFormat from 'dayjs/plugin/customParseFormat.js'
import ElSelect from '@element-plus/components/select'
import { useFormDisabled } from '@element-plus/components/form'
import ElIcon from '@element-plus/components/icon'
import { useLocale, useNamespace } from '@element-plus/hooks'
import { CHANGE_EVENT, UPDATE_MODEL_EVENT } from '@element-plus/constants'
import { timeSelectProps } from './time-select'
import { compareTime, formatTime, nextTime, parseTime } from './utils'
dayjs.extend(customParseFormat)
const { Option: ElOption } = ElSelect
defineOptions({
name: 'ElTimeSelect',
})
defineEmits([CHANGE_EVENT, 'blur', 'focus', 'clear', UPDATE_MODEL_EVENT])
const props = defineProps(timeSelectProps)
const nsInput = useNamespace('input')
const select = ref<typeof ElSelect>()
const _disabled = useFormDisabled()
const { lang } = useLocale()
const value = computed(() => props.modelValue)
const start = computed(() => {
const time = parseTime(props.start)
return time ? formatTime(time) : null
})
const end = computed(() => {
const time = parseTime(props.end)
return time ? formatTime(time) : null
})
const step = computed(() => {
const time = parseTime(props.step)
return time ? formatTime(time) : null
})
const minTime = computed(() => {
const time = parseTime(props.minTime || '')
return time ? formatTime(time) : null
})
const maxTime = computed(() => {
const time = parseTime(props.maxTime || '')
return time ? formatTime(time) : null
})
const items = computed(() => {
const result: { value: string; disabled: boolean }[] = []
const push = (formattedValue: string, rawValue: string) => {
result.push({
value: formattedValue,
disabled:
compareTime(rawValue, minTime.value || '-1:-1') <= 0 ||
compareTime(rawValue, maxTime.value || '100:100') >= 0,
})
}
if (props.start && props.end && props.step) {
let current = start.value
let currentTime: string
while (current && end.value && compareTime(current, end.value) <= 0) {
currentTime = dayjs(current, 'HH:mm')
.locale(lang.value)
.format(props.format)
push(currentTime, current)
current = nextTime(current, step.value!)
}
if (
props.includeEndTime &&
end.value &&
result[result.length - 1]?.value !== end.value
) {
const formattedValue = dayjs(end.value, 'HH:mm')
.locale(lang.value)
.format(props.format)
push(formattedValue, end.value)
}
}
return result
})
const blur = () => {
select.value?.blur?.()
}
const focus = () => {
select.value?.focus?.()
}
defineExpose({
/**
* @description blur the Input component
*/
blur,
/**
* @description focus the Input component
*/
focus,
})
</script>