Appearance
TimeRangeSelector 时间范围选择
用于在一天内选择一个或多个时间区间,适合排班、报表筛选和监控时间段配置。
基础用法
新建位置 00:00 至 00:30;已选区间:08:00 - 12:00 / 14:00 - 18:00
08:00 - 12:00
14:00 - 18:00
网格上用左右方向键定位,Enter 新建;区间上用左右方向键移动,Shift 调整结束,Alt 调整开始,Delete 删除。
0123456789101112131415161718192021222324
[
[
"08:00",
"12:00"
],
[
"14:00",
"18:00"
]
]vue
<template>
<x-time-range-selector v-model="ranges" />
</template>
<script setup lang="ts">
import { ref } from 'vue';
const ranges = ref<[string, string][]>([
['08:00', '12:00'],
['14:00', '18:00'],
]);
</script>禁用时间段
新建位置 00:00 至 00:30;已选区间:07:00 - 11:00 / 15:00 - 19:00
07:00 - 11:00
15:00 - 19:00
网格上用左右方向键定位,Enter 新建;区间上用左右方向键移动,Shift 调整结束,Alt 调整开始,Delete 删除。
0123456789101112131415161718192021222324
[
[
"07:00",
"11:00"
],
[
"15:00",
"19:00"
]
]vue
<template>
<x-time-range-selector
v-model="ranges"
:disabled-ranges="[['12:00', '13:00']]"
:step-minutes="30"
/>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const ranges = ref<[string, string][]>([
['07:00', '11:00'],
['15:00', '19:00'],
]);
</script>场景风格
新建位置 00:00 至 00:30;已选区间:07:00 - 11:00
07:00 - 11:00
网格上用左右方向键定位,Enter 新建;区间上用左右方向键移动,Shift 调整结束,Alt 调整开始,Delete 删除。
0123456789101112131415161718192021222324
新建位置 00:00 至 00:30;已选区间:08:30 - 12:30 / 14:00 - 18:00
08:30 - 12:30
14:00 - 18:00
网格上用左右方向键定位,Enter 新建;区间上用左右方向键移动,Shift 调整结束,Alt 调整开始,Delete 删除。
0123456789101112131415161718192021222324
新建位置 00:00 至 00:30;已选区间:00:00 - 04:00 / 19:00 - 23:00
00:00 - 04:00
19:00 - 23:00
网格上用左右方向键定位,Enter 新建;区间上用左右方向键移动,Shift 调整结束,Alt 调整开始,Delete 删除。
0123456789101112131415161718192021222324
新建位置 00:00 至 00:30;已选区间:09:00 - 13:00 / 15:00 - 19:00
09:00 - 13:00
15:00 - 19:00
网格上用左右方向键定位,Enter 新建;区间上用左右方向键移动,Shift 调整结束,Alt 调整开始,Delete 删除。
0123456789101112131415161718192021222324
新建位置 00:00 至 00:30;已选区间:08:00 - 12:00 / 14:00 - 18:00
08:00 - 12:00
14:00 - 18:00
网格上用左右方向键定位,Enter 新建;区间上用左右方向键移动,Shift 调整结束,Alt 调整开始,Delete 删除。
vue
<template>
<x-time-range-selector
v-model="defaultRanges"
scene="default"
:disabled-ranges="defaultDisabled"
/>
<x-time-range-selector
v-model="scheduleRanges"
scene="schedule"
:disabled-ranges="scheduleDisabled"
/>
<x-time-range-selector
v-model="monitorRanges"
scene="monitor"
:disabled-ranges="monitorDisabled"
/>
<x-time-range-selector
v-model="compactRanges"
scene="compact"
:disabled-ranges="compactDisabled"
/>
<x-time-range-selector
v-model="hiddenCursorRanges"
scene="compact"
:disabled-ranges="hiddenCursorDisabled"
:show-cursor="false"
/>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const defaultRanges = ref<[string, string][]>([['07:00', '11:00']]);
const scheduleRanges = ref<[string, string][]>([
['08:30', '12:30'],
['14:00', '18:00'],
]);
const monitorRanges = ref<[string, string][]>([
['00:00', '04:00'],
['19:00', '23:00'],
]);
const compactRanges = ref<[string, string][]>([
['09:00', '13:00'],
['15:00', '19:00'],
]);
const hiddenCursorRanges = ref<[string, string][]>([
['08:00', '12:00'],
['14:00', '18:00'],
]);
const defaultDisabled = ref<[string, string][]>([['13:00', '15:00']]);
const scheduleDisabled = ref<[string, string][]>([['12:30', '14:00']]);
const monitorDisabled = ref<[string, string][]>([['04:00', '06:00']]);
const compactDisabled = ref<[string, string][]>([['13:00', '14:30']]);
const hiddenCursorDisabled = ref<[string, string][]>([['12:00', '13:00']]);
</script>自定义颜色
新建位置 00:00 至 00:30;已选区间:08:00 - 12:00
08:00 - 12:00
网格上用左右方向键定位,Enter 新建;区间上用左右方向键移动,Shift 调整结束,Alt 调整开始,Delete 删除。
0123456789101112131415161718192021222324
新建位置 00:00 至 00:30;已选区间:09:00 - 13:00
09:00 - 13:00
网格上用左右方向键定位,Enter 新建;区间上用左右方向键移动,Shift 调整结束,Alt 调整开始,Delete 删除。
0123456789101112131415161718192021222324
新建位置 00:00 至 00:30;已选区间:00:00 - 04:00
00:00 - 04:00
网格上用左右方向键定位,Enter 新建;区间上用左右方向键移动,Shift 调整结束,Alt 调整开始,Delete 删除。
0123456789101112131415161718192021222324
新建位置 00:00 至 00:30;已选区间:15:00 - 19:00
15:00 - 19:00
网格上用左右方向键定位,Enter 新建;区间上用左右方向键移动,Shift 调整结束,Alt 调整开始,Delete 删除。
vue
<template>
<x-time-range-selector
v-model="defaultRanges"
color="#0f766e"
:disabled-ranges="defaultDisabled"
/>
<x-time-range-selector
v-model="scheduleRanges"
scene="schedule"
color="#2563eb"
:disabled-ranges="scheduleDisabled"
/>
<x-time-range-selector
v-model="monitorRanges"
scene="monitor"
color="#dc2626"
:disabled-ranges="monitorDisabled"
/>
<x-time-range-selector
v-model="compactRanges"
scene="compact"
color="#16a34a"
:disabled-ranges="compactDisabled"
:show-cursor="false"
/>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const defaultRanges = ref<[string, string][]>([['08:00', '12:00']]);
const scheduleRanges = ref<[string, string][]>([['09:00', '13:00']]);
const monitorRanges = ref<[string, string][]>([['00:00', '04:00']]);
const compactRanges = ref<[string, string][]>([['15:00', '19:00']]);
const defaultDisabled = ref<[string, string][]>([['13:00', '15:00']]);
const scheduleDisabled = ref<[string, string][]>([['13:00', '14:30']]);
const monitorDisabled = ref<[string, string][]>([['04:00', '06:00']]);
const compactDisabled = ref<[string, string][]>([['12:00', '13:30']]);
</script>更细的主题控制可以覆盖组件 CSS 变量。
vue
<template>
<x-time-range-selector v-model="ranges" class="custom-time-range" />
</template>
<script setup lang="ts">
import { ref } from 'vue';
const ranges = ref<[string, string][]>([
['08:00', '12:00'],
['15:00', '19:00'],
]);
</script>
<style scoped>
.custom-time-range {
--x-time-range-selector-color: #0f766e;
--x-time-range-selector-grid-radius: 8px;
--x-time-range-selector-range-height: 34px;
--x-time-range-selector-range-radius: 8px;
}
</style>限制范围数量
新建位置 00:00 至 00:30;已选区间:08:00 - 12:00 / 14:00 - 18:00
08:00 - 12:00
14:00 - 18:00
网格上用左右方向键定位,Enter 新建;区间上用左右方向键移动,Shift 调整结束,Alt 调整开始,Delete 删除。
0123456789101112131415161718192021222324
[
[
"08:00",
"12:00"
],
[
"14:00",
"18:00"
]
]vue
<template>
<x-time-range-selector v-model="ranges" :max-ranges="3" />
</template>
<script setup lang="ts">
import { ref } from 'vue';
const ranges = ref<[string, string][]>([
['08:00', '12:00'],
['14:00', '18:00'],
]);
</script>允许重叠
新建位置 00:00 至 00:30;已选区间:08:00 - 12:00 / 10:00 - 14:00
08:00 - 12:00
10:00 - 14:00
网格上用左右方向键定位,Enter 新建;区间上用左右方向键移动,Shift 调整结束,Alt 调整开始,Delete 删除。
0123456789101112131415161718192021222324
[
[
"08:00",
"12:00"
],
[
"10:00",
"14:00"
]
]vue
<template>
<x-time-range-selector v-model="ranges" overlap-allowed />
</template>
<script setup lang="ts">
import { ref } from 'vue';
const ranges = ref<[string, string][]>([
['08:00', '12:00'],
['10:00', '14:00'],
]);
</script>更细步长
新建位置 00:00 至 00:15;已选区间:08:15 - 12:15
08:15 - 12:15
网格上用左右方向键定位,Enter 新建;区间上用左右方向键移动,Shift 调整结束,Alt 调整开始,Delete 删除。
0123456789101112131415161718192021222324
[
[
"08:15",
"12:15"
]
]vue
<template>
<x-time-range-selector v-model="ranges" :step-minutes="15" />
</template>
<script setup lang="ts">
import { ref } from 'vue';
const ranges = ref<[string, string][]>([
['08:15', '12:15'],
]);
</script>整体禁用与只读
新建位置 00:00 至 00:30;已选区间:08:00 - 12:00
08:00 - 12:00
网格上用左右方向键定位,Enter 新建;区间上用左右方向键移动,Shift 调整结束,Alt 调整开始,Delete 删除。
0123456789101112131415161718192021222324
vue
<template>
<x-space><x-checkbox v-model="disabled">禁用</x-checkbox><x-checkbox v-model="readonly">只读</x-checkbox></x-space>
<x-time-range-selector v-model="ranges" :disabled="disabled" :readonly="readonly" />
</template>
<script setup lang="ts">
import { ref } from 'vue';
const ranges = ref<[string, string][]>([['08:00', '12:00']]);
const disabled = ref(false);
const readonly = ref(false);
</script>禁用时退出 Tab 序列,只读时仍可聚焦查看。两种状态都阻止创建、移动、缩放与删除;拖拽过程中切换状态会取消预览并恢复外部值。
键盘与删除事件
新建位置 00:00 至 00:30;已选区间:暂无数据
网格上用左右方向键定位,Enter 新建;区间上用左右方向键移动,Shift 调整结束,Alt 调整开始,Delete 删除。
0123456789101112131415161718192021222324
vue
<template>
<x-time-range-selector v-model="ranges" aria-label="排班时间段" :disabled-ranges="[['12:00', '13:00']]" :max-ranges="3"
@change="onChange" @remove="onRemove" />
<p>{{ log }};{{ removed }}</p>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const ranges = ref<[string, string][]>([]);
const log = ref('等待操作');
const removed = ref('等待删除');
const onChange = (value: [string, string][]) => { log.value = `change: ${JSON.stringify(value)}`; };
const onRemove = (value: [string, string]) => { removed.value = `remove: ${value.join(' - ')}`; };
</script>Home / End 定位到一天的首尾时间块。键盘每次移动一个 stepMinutes,遵守禁区、重叠、最大数量和 24:00 边界。双击区间或在区间聚焦后按 Delete / Backspace 删除。删除先触发 remove,再触发 update:modelValue 和 change。
Form 禁用、校验与重置
至少选择一个时间段
vue
<template>
<x-checkbox v-model="disabled">禁用整个表单</x-checkbox>
<x-form ref="formRef" :model="form" :disabled="disabled" layout="vertical">
<x-form-item field="ranges" label="工作时段" :rules="{ type: 'array', minLength: 1, message: '至少选择一个时间段' }">
<x-time-range-selector v-model="form.ranges" />
</x-form-item>
</x-form>
<x-space><x-button @click="validate">校验</x-button><x-button @click="reset">重置</x-button></x-space>
<p>{{ result }}</p>
</template>
<script setup lang="ts">
import { reactive, ref } from 'vue';
import type { FormInstance } from 'x-next';
const form = reactive({ ranges: [] as [string, string][] });
const formRef = ref<FormInstance>();
const disabled = ref(false);
const result = ref('至少选择一个时间段');
const validate = async () => { result.value = (await formRef.value!.validate()) ? '请添加时间段' : '校验通过'; };
const reset = () => { formRef.value!.resetFields(); result.value = '已重置'; };
</script>用户完成拖拽或键盘修改时触发 Form 的 change 校验;外部模型同步不会重复触发 change。
受控接收与拒绝更新
新建位置 00:00 至 00:30;已选区间:08:00 - 12:00
08:00 - 12:00
网格上用左右方向键定位,Enter 新建;区间上用左右方向键移动,Shift 调整结束,Alt 调整开始,Delete 删除。
0123456789101112131415161718192021222324
vue
<template>
<x-checkbox v-model="accept">接收修改</x-checkbox>
<x-time-range-selector :model-value="ranges" @update:model-value="handleUpdate" />
<p>{{ log }}</p>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const ranges = ref<[string, string][]>([['08:00', '12:00']]);
const accept = ref(false);
const log = ref('当前拒绝修改,操作后会恢复');
const handleUpdate = (value: [string, string][]) => {
log.value = `请求:${JSON.stringify(value)},${accept.value ? '已接收' : '已拒绝'}`;
if (accept.value) ranges.value = value;
};
</script>拖拽中显示预览,结束后提交更新请求。父级未同步接收时,下一个渲染周期恢复 modelValue;键盘操作也遵循此规则。外部模型更新会终止正在进行的拖拽。
按需导入
ts
import { TimeRangeSelector } from 'x-next';样式按需引入(base.css 为共享基础层,多个组件只需引入一次):
ts
import 'x-next/style/base.css';
import 'x-next/style/time-range-selector.css';Props
| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
modelValue | 时间范围数组 | [string, string][] | 必填 |
color | 组件主色,会写入 --x-time-range-selector-color 并派生轨道、选中段和手柄颜色 | string | undefined |
scene | 场景风格,适配常规筛选、排班预约、监控时段和紧凑筛选 | 'default' | 'schedule' | 'monitor' | 'compact' | 'default' |
showCursor | 是否显示下方 0-24 小时游标 | boolean | true |
overlapAllowed | 是否允许时间段重叠 | boolean | false |
stepMinutes | 时间块步长,单位分钟;非法或不能整除 1440 时降级为 30 | number | 30 |
disabledRanges | 禁用时间范围 | [string, string][] | [] |
disabled | 整体禁用,继承 Form / FormItem 禁用状态 | boolean | false |
readonly | 只读,允许聚焦但不允许修改 | boolean | false |
maxRanges | 最多可创建范围数量 | number | Infinity |
Events
| 事件名 | 说明 | 回调参数 |
|---|---|---|
update:modelValue | 时间范围提交或约束重新归一化后触发 | value: [string, string][] |
change | 用户完成修改且值变化时触发,外部同步不触发 | value: [string, string][] |
remove | 用户删除时间段时触发 | range: [string, string] |
交互说明
- 在时间轴空白区域按下并拖动可创建范围。
- 拖动范围主体可移动时间段,拖动过程中会保持原区间宽度。
- 拖动左右边缘可调整开始和结束时间。
- 双击已选范围可删除。
- 当
overlapAllowed为false时,组件会阻止创建或拖入重叠区间。 - 禁用时间段不会被纳入最终值,拖拽靠近禁用时间段时会停在边界。
disabledRanges 只限制指定时间段;整体禁用请使用 disabled。拖拽时显示内部预览,外部模型更新会终止当前拖拽并同步值。请使用 v-model 接收最终结果;父级拒绝更新时会在下一渲染周期恢复 modelValue。