mirror of
https://github.com/element-plus/element-plus.git
synced 2026-03-13 07:51:17 +08:00
feat(components): [el-time-select] support custom format (e.g. 12-hour) (#5309)
This commit is contained in:
@@ -7,6 +7,8 @@ lang: en-US
|
||||
|
||||
Use Time Select for time input.
|
||||
|
||||
The available time range is 00:00 to 23:59
|
||||
|
||||
## Fixed time picker
|
||||
|
||||
Provide a list of fixed time for users to choose.
|
||||
@@ -17,9 +19,27 @@ time-select/basic
|
||||
|
||||
:::
|
||||
|
||||
## Time Formats
|
||||
|
||||
Use `format` to control format of time(hours and minutes).
|
||||
|
||||
Check the list [here](https://day.js.org/docs/en/display/format#list-of-all-available-formats) of all available formats of Day.js.
|
||||
|
||||
:::warning
|
||||
|
||||
Pay attention to capitalization
|
||||
|
||||
:::
|
||||
|
||||
:::demo
|
||||
|
||||
time-select/time-formats
|
||||
|
||||
:::
|
||||
|
||||
## Fixed time range
|
||||
|
||||
If start time is picked at first, then the end time will change accordingly.
|
||||
If start( end ) time is picked at first, then the status of end( start ) time's options will change accordingly.
|
||||
|
||||
:::demo
|
||||
|
||||
@@ -29,22 +49,23 @@ time-select/time-range
|
||||
|
||||
## Attributes
|
||||
|
||||
| Attribute | Description | Type | Accepted Values | Default |
|
||||
| --------------------- | -------------------------------------------------------- | ------------------ | ----------------------- | ----------- |
|
||||
| model-value / v-model | binding value | string | — | — |
|
||||
| disabled | whether TimeSelect is disabled | boolean | — | false |
|
||||
| editable | whether the input is editable | boolean | — | true |
|
||||
| clearable | whether to show clear button | boolean | — | true |
|
||||
| size | size of Input | string | large / default / small | default |
|
||||
| placeholder | placeholder in non-range mode | string | — | — |
|
||||
| name | same as `name` in native input | string | — | — |
|
||||
| prefix-icon | Custom prefix icon component | string / Component | — | Clock |
|
||||
| clear-icon | Custom clear icon component | string / Component | — | CircleClose |
|
||||
| start | start time | string | — | 09:00 |
|
||||
| end | end time | string | — | 18:00 |
|
||||
| step | time step | string | — | 00:30 |
|
||||
| min-time | minimum time, any time before this time will be disabled | string | — | 00:00 |
|
||||
| max-time | maximum time, any time after this time will be disabled | string | — | — |
|
||||
| Attribute | Description | Type | Accepted Values | Default |
|
||||
| --------------------- | -------------------------------------------------------- | ------------------ | -------------------------------------------------------------------------------------- | ----------- |
|
||||
| model-value / v-model | binding value | string | — | — |
|
||||
| disabled | whether TimeSelect is disabled | boolean | — | false |
|
||||
| editable | whether the input is editable | boolean | — | true |
|
||||
| clearable | whether to show clear button | boolean | — | true |
|
||||
| size | size of Input | string | large / default / small | default |
|
||||
| placeholder | placeholder in non-range mode | string | — | — |
|
||||
| name | same as `name` in native input | string | — | — |
|
||||
| prefix-icon | Custom prefix icon component | string / Component | — | Clock |
|
||||
| clear-icon | Custom clear icon component | string / Component | — | CircleClose |
|
||||
| start | start time | string | — | 09:00 |
|
||||
| end | end time | string | — | 18:00 |
|
||||
| step | time step | string | — | 00:30 |
|
||||
| min-time | minimum time, any time before this time will be disabled | string | — | 00:00 |
|
||||
| max-time | maximum time, any time after this time will be disabled | string | — | — |
|
||||
| format | set format of time | string | see [formats](https://day.js.org/docs/en/display/format#list-of-all-available-formats) | HH:mm |
|
||||
|
||||
## Events
|
||||
|
||||
|
||||
17
docs/examples/time-select/time-formats.vue
Normal file
17
docs/examples/time-select/time-formats.vue
Normal file
@@ -0,0 +1,17 @@
|
||||
<template>
|
||||
<el-time-select
|
||||
v-model="value"
|
||||
start="00:00"
|
||||
step="00:30"
|
||||
end="23:59"
|
||||
placeholder="Select time"
|
||||
format="hh:mm A"
|
||||
>
|
||||
</el-time-select>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
const value = ref('')
|
||||
</script>
|
||||
@@ -2,6 +2,7 @@
|
||||
<div class="demo-time-range">
|
||||
<el-time-select
|
||||
v-model="startTime"
|
||||
:max-time="endTime"
|
||||
class="mr-4"
|
||||
placeholder="Start time"
|
||||
start="08:30"
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
import { nextTick } from 'vue'
|
||||
import { mount } from '@vue/test-utils'
|
||||
import dayjs from 'dayjs'
|
||||
import customParseFormat from 'dayjs/plugin/customParseFormat'
|
||||
import Select from '@element-plus/components/select'
|
||||
import { sleep } from '@element-plus/test-utils'
|
||||
import TimeSelect from '../src/time-select.vue'
|
||||
dayjs.extend(customParseFormat)
|
||||
|
||||
const { Option } = Select
|
||||
|
||||
@@ -170,4 +173,23 @@ describe('TimeSelect', () => {
|
||||
const attr = popperEl.getAttribute('aria-hidden')
|
||||
expect(attr).toEqual('true')
|
||||
})
|
||||
|
||||
it('set format', async () => {
|
||||
const wrapper = _mount(
|
||||
`<el-time-select
|
||||
v-model="value"
|
||||
start="13:00"
|
||||
step="00:30"
|
||||
end="13:30"
|
||||
format="hh:mm A"
|
||||
>
|
||||
</el-time-select>`,
|
||||
() => ({ value: '' })
|
||||
)
|
||||
const input = wrapper.find('.el-input__inner')
|
||||
await input.trigger('click')
|
||||
await nextTick()
|
||||
const option = document.querySelector('.el-select-dropdown__item')
|
||||
expect(option.textContent).toBe('01:00 PM')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -31,12 +31,15 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, computed, ref } from 'vue'
|
||||
import dayjs from 'dayjs'
|
||||
import customParseFormat from 'dayjs/plugin/customParseFormat'
|
||||
import ElSelect from '@element-plus/components/select'
|
||||
import ElIcon from '@element-plus/components/icon'
|
||||
import { CircleClose, Clock } from '@element-plus/icons-vue'
|
||||
|
||||
import type { PropType, Component } from 'vue'
|
||||
import type { ComponentSize } from '@element-plus/utils/types'
|
||||
dayjs.extend(customParseFormat)
|
||||
|
||||
const { Option: ElOption } = ElSelect
|
||||
|
||||
@@ -48,8 +51,14 @@ interface Time {
|
||||
const parseTime = (time: string): null | Time => {
|
||||
const values = (time || '').split(':')
|
||||
if (values.length >= 2) {
|
||||
const hours = parseInt(values[0], 10)
|
||||
let hours = parseInt(values[0], 10)
|
||||
const minutes = parseInt(values[1], 10)
|
||||
const timeUpper = time.toUpperCase()
|
||||
if (timeUpper.includes('AM') && hours === 12) {
|
||||
hours = 0
|
||||
} else if (timeUpper.includes('PM') && hours !== 12) {
|
||||
hours += 12
|
||||
}
|
||||
return {
|
||||
hours,
|
||||
minutes,
|
||||
@@ -67,10 +76,11 @@ const compareTime = (time1: string, time2: string): number => {
|
||||
}
|
||||
return minutes1 > minutes2 ? 1 : -1
|
||||
}
|
||||
const padTime = (time: number | string) => {
|
||||
return `${time}`.padStart(2, '0')
|
||||
}
|
||||
const formatTime = (time: Time): string => {
|
||||
return `${time.hours < 10 ? `0${time.hours}` : time.hours}:${
|
||||
time.minutes < 10 ? `0${time.minutes}` : time.minutes
|
||||
}`
|
||||
return `${padTime(time.hours)}:${padTime(time.minutes)}`
|
||||
}
|
||||
const nextTime = (time: string, step: string): string => {
|
||||
const timeValue = parseTime(time)
|
||||
@@ -94,6 +104,10 @@ export default defineComponent({
|
||||
event: 'change',
|
||||
},
|
||||
props: {
|
||||
format: {
|
||||
type: String,
|
||||
default: 'HH:mm',
|
||||
},
|
||||
modelValue: String,
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
@@ -155,18 +169,40 @@ export default defineComponent({
|
||||
// computed
|
||||
const select = ref(null)
|
||||
const value = computed(() => props.modelValue)
|
||||
const start = computed(() => {
|
||||
const time = parseTime(props.start)
|
||||
return formatTime(time)
|
||||
})
|
||||
const end = computed(() => {
|
||||
const time = parseTime(props.end)
|
||||
return formatTime(time)
|
||||
})
|
||||
const step = computed(() => {
|
||||
const time = parseTime(props.step)
|
||||
return formatTime(time)
|
||||
})
|
||||
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 = []
|
||||
if (props.start && props.end && props.step) {
|
||||
let current = props.start
|
||||
while (compareTime(current, props.end) <= 0) {
|
||||
let current = start.value
|
||||
let currentTime
|
||||
while (compareTime(current, end.value) <= 0) {
|
||||
currentTime = dayjs(current, 'HH:mm').format(props.format)
|
||||
result.push({
|
||||
value: current,
|
||||
value: currentTime,
|
||||
disabled:
|
||||
compareTime(current, props.minTime || '-1:-1') <= 0 ||
|
||||
compareTime(current, props.maxTime || '100:100') >= 0,
|
||||
compareTime(current, minTime.value || '-1:-1') <= 0 ||
|
||||
compareTime(current, maxTime.value || '100:100') >= 0,
|
||||
})
|
||||
current = nextTime(current, props.step)
|
||||
current = nextTime(current, step.value)
|
||||
}
|
||||
}
|
||||
return result
|
||||
|
||||
Reference in New Issue
Block a user