使用场景 ​
从固定起止区间按步长生成时间选项,用于预约和排班。正常选择提交格式化时间文本,清空时直接输出原生 valueOnClear 结果。
原生默认模型 ​
未设置行为属性时由原生控件解析默认值。以下完整 SFC 对照显式 undefined、null 和空字符串;输出保留原始模型类型,不把清空值统一为 null。固定原生版本的非法输入诊断与兼容限制仍按原生处理。
原生默认模型
<template>
<section class="native-values-example">
<p class="example-paragraph">使用原生模型和默认值,选择提交格式化时间文本,清空输出原生配置值。</p>
<AsamTimeSelect v-model="value" clearable @update:model-value="updates++" />
<AsamButton type="default" native-type="button" @click="value = undefined"
>显式 undefined</AsamButton
>
<AsamButton type="default" native-type="button" @click="value = null">显式 null</AsamButton>
<AsamButton type="default" native-type="button" @click="value = ''"
>显式空字符串</AsamButton
>
<output>{{ summary }};更新次数 {{ updates }}</output>
</section>
</template>
<script lang="ts" setup>
import { computed, ref } from 'vue';
import { AsamButton, AsamTimeSelect } from '@asam-ui/ui';
import type { AsamTimeSelectValue } from '@asam-ui/ui';
defineOptions({ name: 'AsamTimeSelectNativeValuesExample' });
const value = ref<AsamTimeSelectValue>();
const updates = ref(0);
const summary = computed(() =>
value.value === undefined
? 'undefined'
: value.value instanceof Date
? 'Date ' + value.value.toISOString()
: JSON.stringify(value.value)
);
</script>
<style scoped>
.native-values-example {
display: grid;
gap: var(--asam-space-md);
}
</style>
<style scoped>
p:where(.example-paragraph) {
margin-block: 16px;
line-height: 1.8;
overflow-wrap: anywhere;
}
</style>
<template>
<section class="native-values-example">
<p class="example-paragraph">使用原生模型和默认值,选择提交格式化时间文本,清空输出原生配置值。</p>
<AsamTimeSelect v-model="value" clearable @update:model-value="updates++" />
<AsamButton type="default" native-type="button" @click="value = undefined"
>显式 undefined</AsamButton
>
<AsamButton type="default" native-type="button" @click="value = null">显式 null</AsamButton>
<AsamButton type="default" native-type="button" @click="value = ''"
>显式空字符串</AsamButton
>
<output>{{ summary }};更新次数 {{ updates }}</output>
</section>
</template>
<script setup>
import { computed, ref } from 'vue';
import { AsamButton, AsamTimeSelect } from '@asam-ui/ui';
defineOptions({ name: 'AsamTimeSelectNativeValuesExample' });
const value = ref();
const updates = ref(0);
const summary = computed(() =>
value.value === undefined
? 'undefined'
: value.value instanceof Date
? 'Date ' + value.value.toISOString()
: JSON.stringify(value.value)
);
</script>
<style scoped>
.native-values-example {
display: grid;
gap: var(--asam-space-md);
}
</style>
<style scoped>
p:where(.example-paragraph) {
margin-block: 16px;
line-height: 1.8;
overflow-wrap: anywhere;
}
</style>
格式、清空与禁用 ​
模型初始为空;选择后显示当前值。disabled 由调用方切换,clear 的行为与 update:modelValue 分开。
格式、清空与禁用
<template>
<div class="example">
<AsamTimeSelect
v-model="value"
v-bind="{
start: '08:00',
step: '00:30',
end: '18:00',
clearable: true,
'aria-label': '选择时间'
}"
:disabled="disabled"
/>
<AsamButton type="default" @click="disabled = !disabled"> 切换禁用 </AsamButton>
<output>模型:{{ value }};禁用:{{ disabled }}</output>
</div>
</template>
<script lang="ts" setup>
import type { AsamTimeSelectValue } from '@asam-ui/ui';
defineOptions({ name: 'AsamTimeSelectBasicExample' });
import { ref } from 'vue';
import { AsamTimeSelect, AsamButton } from '@asam-ui/ui';
const value = ref<AsamTimeSelectValue>(null);
const disabled = ref(false);
</script>
<style scoped>
.example {
display: grid;
gap: var(--asam-space-md, 16px);
min-width: 0;
}
.row {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--asam-space-sm, 8px);
}
.density-grid {
display: grid;
gap: var(--asam-space-md, 16px);
grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
}
section {
display: grid;
gap: var(--asam-space-sm, 8px);
min-width: 0;
}
output {
overflow-wrap: anywhere;
color: var(--asam-color-text-secondary);
}
</style>
<template>
<div class="example">
<AsamTimeSelect
v-model="value"
v-bind="{
start: '08:00',
step: '00:30',
end: '18:00',
clearable: true,
'aria-label': '选择时间'
}"
:disabled="disabled"
/>
<AsamButton type="default" @click="disabled = !disabled"> 切换禁用 </AsamButton>
<output>模型:{{ value }};禁用:{{ disabled }}</output>
</div>
</template>
<script setup>
defineOptions({ name: 'AsamTimeSelectBasicExample' });
import { ref } from 'vue';
import { AsamTimeSelect, AsamButton } from '@asam-ui/ui';
const value = ref(null);
const disabled = ref(false);
</script>
<style scoped>
.example {
display: grid;
gap: var(--asam-space-md, 16px);
min-width: 0;
}
.row {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--asam-space-sm, 8px);
}
.density-grid {
display: grid;
gap: var(--asam-space-md, 16px);
grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
}
section {
display: grid;
gap: var(--asam-space-sm, 8px);
min-width: 0;
}
output {
overflow-wrap: anywhere;
color: var(--asam-color-text-secondary);
}
</style>
动态最早时间 ​
minTime/maxTime 限制可选范围,includeEndTime 可包含终点。修改前一个值后,调用方决定是否重置后一个值。
动态最早时间
<template>
<div class="example">
<AsamTimeSelect v-model="start" v-bind="{ start: '08:00', step: '00:30', end: '18:00' }" />
<AsamTimeSelect
v-model="end"
v-bind="{ start: '08:00', step: '00:30', end: '18:00' }"
:min-time="typeof start === 'string' ? start : undefined"
/>
<output>预约:{{ start }} 至 {{ end }}</output>
</div>
</template>
<script lang="ts" setup>
import type { AsamTimeSelectValue } from '@asam-ui/ui';
defineOptions({ name: 'AsamTimeSelectBoundsExample' });
import { ref } from 'vue';
import { AsamTimeSelect } from '@asam-ui/ui';
const start = ref<AsamTimeSelectValue>(null);
const end = ref<AsamTimeSelectValue>(null);
</script>
<style scoped>
.example {
display: grid;
gap: var(--asam-space-md, 16px);
min-width: 0;
}
.row {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--asam-space-sm, 8px);
}
.density-grid {
display: grid;
gap: var(--asam-space-md, 16px);
grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
}
section {
display: grid;
gap: var(--asam-space-sm, 8px);
min-width: 0;
}
output {
overflow-wrap: anywhere;
color: var(--asam-color-text-secondary);
}
</style>
<template>
<div class="example">
<AsamTimeSelect v-model="start" v-bind="{ start: '08:00', step: '00:30', end: '18:00' }" />
<AsamTimeSelect
v-model="end"
v-bind="{ start: '08:00', step: '00:30', end: '18:00' }"
:min-time="typeof start === 'string' ? start : undefined"
/>
<output>预约:{{ start }} 至 {{ end }}</output>
</div>
</template>
<script setup>
defineOptions({ name: 'AsamTimeSelectBoundsExample' });
import { ref } from 'vue';
import { AsamTimeSelect } from '@asam-ui/ui';
const start = ref(null);
const end = ref(null);
</script>
<style scoped>
.example {
display: grid;
gap: var(--asam-space-md, 16px);
min-width: 0;
}
.row {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--asam-space-sm, 8px);
}
.density-grid {
display: grid;
gap: var(--asam-space-md, 16px);
grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
}
section {
display: grid;
gap: var(--asam-space-sm, 8px);
min-width: 0;
}
output {
overflow-wrap: anywhere;
color: var(--asam-color-text-secondary);
}
</style>
公开实例操作 ​
focus/blur 访问实际输入。
公开实例操作
<template>
<div class="example">
<AsamTimeSelect
ref="control"
v-bind="{ start: '08:00', step: '00:30', end: '18:00' }"
v-model="value"
/>
<div class="row">
<AsamButton type="default" @click="control?.focus()"> 聚焦 </AsamButton>
<AsamButton type="default" @click="control?.blur()"> 失焦 </AsamButton>
</div>
</div>
</template>
<script lang="ts" setup>
import type { AsamTimeSelectValue } from '@asam-ui/ui';
defineOptions({ name: 'AsamTimeSelectInstanceExample' });
import { ref } from 'vue';
import { AsamTimeSelect, AsamButton } from '@asam-ui/ui';
import type { AsamTimeSelectExpose } from '@asam-ui/ui';
const control = ref<AsamTimeSelectExpose>();
const value = ref<AsamTimeSelectValue>(null);
</script>
<style scoped>
.example {
display: grid;
gap: var(--asam-space-md, 16px);
min-width: 0;
}
.row {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--asam-space-sm, 8px);
}
.density-grid {
display: grid;
gap: var(--asam-space-md, 16px);
grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
}
section {
display: grid;
gap: var(--asam-space-sm, 8px);
min-width: 0;
}
output {
overflow-wrap: anywhere;
color: var(--asam-color-text-secondary);
}
</style>
<template>
<div class="example">
<AsamTimeSelect
ref="control"
v-bind="{ start: '08:00', step: '00:30', end: '18:00' }"
v-model="value"
/>
<div class="row">
<AsamButton type="default" @click="control?.focus()"> 聚焦 </AsamButton>
<AsamButton type="default" @click="control?.blur()"> 失焦 </AsamButton>
</div>
</div>
</template>
<script setup>
defineOptions({ name: 'AsamTimeSelectInstanceExample' });
import { ref } from 'vue';
import { AsamTimeSelect, AsamButton } from '@asam-ui/ui';
const control = ref();
const value = ref(null);
</script>
<style scoped>
.example {
display: grid;
gap: var(--asam-space-md, 16px);
min-width: 0;
}
.row {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--asam-space-sm, 8px);
}
.density-grid {
display: grid;
gap: var(--asam-space-md, 16px);
grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
}
section {
display: grid;
gap: var(--asam-space-sm, 8px);
min-width: 0;
}
output {
overflow-wrap: anywhere;
color: var(--asam-color-text-secondary);
}
</style>
四档尺寸与上下文继承 ​
四个实例分别显式使用 large、big、default、small。下面省略 size 的实例随 ConfigProvider 响应切换;显式 size 覆盖祖先。面板本身没有 size 契约的入口不附加虚构尺寸属性。
四档尺寸与上下文继承
<template>
<div class="example">
<div class="density-grid">
<section>
<strong> large </strong>
<AsamTimeSelect
v-bind="{ size: 'large', start: '08:00', step: '00:30', end: '18:00' }"
/>
</section>
<section>
<strong> big </strong>
<AsamTimeSelect
v-bind="{ size: 'big', start: '08:00', step: '00:30', end: '18:00' }"
/>
</section>
<section>
<strong> default </strong>
<AsamTimeSelect
v-bind="{ size: 'default', start: '08:00', step: '00:30', end: '18:00' }"
/>
</section>
<section>
<strong> small </strong>
<AsamTimeSelect
v-bind="{ size: 'small', start: '08:00', step: '00:30', end: '18:00' }"
/>
</section>
</div>
<AsamConfigProvider :size="density">
<section>
<AsamTimeSelect start="08:00" step="00:30" end="18:00" />
</section>
</AsamConfigProvider>
<div class="row">
<AsamButton type="default" @click="density = 'small'"> 继承 small </AsamButton>
<AsamButton type="default" @click="density = 'big'"> 继承 big </AsamButton>
</div>
<output>配置提供器:{{ density }}</output>
</div>
</template>
<script lang="ts" setup>
defineOptions({ name: 'AsamTimeSelectSizesExample' });
import { ref } from 'vue';
import { AsamTimeSelect, AsamConfigProvider, AsamButton } from '@asam-ui/ui';
import type { AsamControlSize } from '@asam-ui/ui';
const density = ref<AsamControlSize>('big');
</script>
<style scoped>
.example {
display: grid;
gap: var(--asam-space-md, 16px);
min-width: 0;
}
.row {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--asam-space-sm, 8px);
}
.density-grid {
display: grid;
gap: var(--asam-space-md, 16px);
grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
}
section {
display: grid;
gap: var(--asam-space-sm, 8px);
min-width: 0;
}
output {
overflow-wrap: anywhere;
color: var(--asam-color-text-secondary);
}
</style>
<template>
<div class="example">
<div class="density-grid">
<section>
<strong> large </strong>
<AsamTimeSelect
v-bind="{ size: 'large', start: '08:00', step: '00:30', end: '18:00' }"
/>
</section>
<section>
<strong> big </strong>
<AsamTimeSelect
v-bind="{ size: 'big', start: '08:00', step: '00:30', end: '18:00' }"
/>
</section>
<section>
<strong> default </strong>
<AsamTimeSelect
v-bind="{ size: 'default', start: '08:00', step: '00:30', end: '18:00' }"
/>
</section>
<section>
<strong> small </strong>
<AsamTimeSelect
v-bind="{ size: 'small', start: '08:00', step: '00:30', end: '18:00' }"
/>
</section>
</div>
<AsamConfigProvider :size="density">
<section>
<AsamTimeSelect start="08:00" step="00:30" end="18:00" />
</section>
</AsamConfigProvider>
<div class="row">
<AsamButton type="default" @click="density = 'small'"> 继承 small </AsamButton>
<AsamButton type="default" @click="density = 'big'"> 继承 big </AsamButton>
</div>
<output>配置提供器:{{ density }}</output>
</div>
</template>
<script setup>
defineOptions({ name: 'AsamTimeSelectSizesExample' });
import { ref } from 'vue';
import { AsamTimeSelect, AsamConfigProvider, AsamButton } from '@asam-ui/ui';
const density = ref('big');
</script>
<style scoped>
.example {
display: grid;
gap: var(--asam-space-md, 16px);
min-width: 0;
}
.row {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--asam-space-sm, 8px);
}
.density-grid {
display: grid;
gap: var(--asam-space-md, 16px);
grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
}
section {
display: grid;
gap: var(--asam-space-sm, 8px);
min-width: 0;
}
output {
overflow-wrap: anywhere;
color: var(--asam-color-text-secondary);
}
</style>
ASAM 扩展与迁移 ​
固定 2.14.7 对无法解析或负数的 start/end,以及无法解析、负数或零步长 step 给出诊断,并分别回退到 09:00、18:00、00:30,避免无穷生成选项。 完整说明。
start 大于 end 且 includeEndTime=false 时没有选项;includeEndTime=true 时仍追加 end。 完整说明。
ASAM 四档 size 与表单、ConfigProvider 继承一致。 完整说明。
API 阅读方式 ​
下方 Props、Events、Slots、Exposes 按当前实际公开类型与运行默认值生成。组合属性按分支生效,不能任意混搭值模式。标为“未知 / 未声明”的默认值不代表 false 或空值。源码区域提供对应语言的独立 Demo.vue,可直接复制或下载;本地辅助组件、数据和素材已内联到当前文件。
固定 2.14.7 完整用法 ​
下面以 ASAM 公开组件和图标入口承接固定 2.14.7 完整用途,保留 TS/JS 完整示例。基础入口使用原生默认值,未指定 valueFormat 的日期/时间选择保持 Date 模型。
基础用法 ​
基础用法
<template>
<AsamTimeSelect
v-model="value"
style="width: 240px"
start="08:30"
step="00:15"
end="18:30"
placeholder="选择时间"
/>
</template>
<script lang="ts" setup>
import type { AsamTimeSelectValue } from '@asam-ui/ui';
import { AsamTimeSelect } from '@asam-ui/ui';
defineOptions({ name: 'AsamTimeSelectofficialtimeselectbasicExample' });
import { ref } from 'vue';
const value = ref<AsamTimeSelectValue>('');
</script>
<template>
<AsamTimeSelect
v-model="value"
style="width: 240px"
start="08:30"
step="00:15"
end="18:30"
placeholder="选择时间"
/>
</template>
<script setup>
import { AsamTimeSelect } from '@asam-ui/ui';
defineOptions({ name: 'AsamTimeSelectofficialtimeselectbasicExample' });
import { ref } from 'vue';
const value = ref('');
</script>
时间格式 ​
时间格式
<template>
<AsamTimeSelect
v-model="value"
style="width: 240px"
start="00:00"
step="00:30"
end="23:59"
placeholder="选择时间"
format="hh:mm A"
/>
</template>
<script lang="ts" setup>
import type { AsamTimeSelectValue } from '@asam-ui/ui';
import { AsamTimeSelect } from '@asam-ui/ui';
defineOptions({ name: 'AsamTimeSelectofficialtimeselecttimeformatsExample' });
import { ref } from 'vue';
const value = ref<AsamTimeSelectValue>('');
</script>
<template>
<AsamTimeSelect
v-model="value"
style="width: 240px"
start="00:00"
step="00:30"
end="23:59"
placeholder="选择时间"
format="hh:mm A"
/>
</template>
<script setup>
import { AsamTimeSelect } from '@asam-ui/ui';
defineOptions({ name: 'AsamTimeSelectofficialtimeselecttimeformatsExample' });
import { ref } from 'vue';
const value = ref('');
</script>
时间范围 ​
时间范围
<template>
<div class="demo-time-range flex flex-wrap gap-4">
<AsamTimeSelect
v-model="startTime"
style="width: 240px"
:max-time="typeof endTime === 'string' ? endTime : undefined"
placeholder="开始时间"
start="08:30"
step="00:15"
end="18:30"
/>
<AsamTimeSelect
v-model="endTime"
style="width: 240px"
:min-time="typeof startTime === 'string' ? startTime : undefined"
placeholder="结束时间"
start="08:30"
step="00:15"
end="18:30"
/>
</div>
</template>
<script lang="ts" setup>
import type { AsamTimeSelectValue } from '@asam-ui/ui';
import { AsamTimeSelect } from '@asam-ui/ui';
defineOptions({ name: 'AsamTimeSelectofficialtimeselecttimerangeExample' });
import { ref } from 'vue';
const startTime = ref<AsamTimeSelectValue>('');
const endTime = ref<AsamTimeSelectValue>('');
</script>
<style scoped>
/* Keep layout utilities local so the downloaded SFC needs no CSS preset. */
.flex {
display: flex;
}
.flex-wrap {
flex-wrap: wrap;
}
.gap-4 {
gap: var(--asam-space-lg);
}
</style>
<template>
<div class="demo-time-range flex flex-wrap gap-4">
<AsamTimeSelect
v-model="startTime"
style="width: 240px"
:max-time="typeof endTime === 'string' ? endTime : undefined"
placeholder="开始时间"
start="08:30"
step="00:15"
end="18:30"
/>
<AsamTimeSelect
v-model="endTime"
style="width: 240px"
:min-time="typeof startTime === 'string' ? startTime : undefined"
placeholder="结束时间"
start="08:30"
step="00:15"
end="18:30"
/>
</div>
</template>
<script setup>
import { AsamTimeSelect } from '@asam-ui/ui';
defineOptions({ name: 'AsamTimeSelectofficialtimeselecttimerangeExample' });
import { ref } from 'vue';
const startTime = ref('');
const endTime = ref('');
</script>
<style scoped>
/* Keep layout utilities local so the downloaded SFC needs no CSS preset. */
.flex {
display: flex;
}
.flex-wrap {
flex-wrap: wrap;
}
.gap-4 {
gap: var(--asam-space-lg);
}
</style>
非法时间配置与安全回退 ​
非法时间配置与安全回退
<template>
<section class="demo-layout-1">
<label for="ui028-scenario">配置场景</label>
<AsamSelect id="ui028-scenario" v-model="scenario">
<AsamOption
v-for="(config, name) in configurations"
:key="name"
:value="name"
:label="name"
>
{{ name }}
</AsamOption>
</AsamSelect>
<AsamCheckboxItem v-model="includeEndTime">包含终点</AsamCheckboxItem>
<AsamCheckboxItem v-model="boundEnd">minTime 等于 end</AsamCheckboxItem>
<!-- prettier-ignore -->
<AsamTimeSelect
v-model="value"
v-bind="configuration"
:min-time="boundEnd ? configuration.end : undefined"
:include-end-time="includeEndTime"
:teleported="false"
/>
<output>输入配置 {{ configuration }};显示格式 HH:mm;选择提交模型 {{ value }}</output>
</section>
</template>
<script lang="ts" setup>
import type { AsamTimeSelectValue } from '@asam-ui/ui';
defineOptions({ name: 'AsamTimeSelectinvalidconfigExample' });
import { computed, ref, watch } from 'vue';
import { AsamSelect, AsamOption, AsamCheckboxItem, AsamTimeSelect } from '@asam-ui/ui';
const value = ref<AsamTimeSelectValue>(null);
const configurations = {
正常: { start: '09:00', end: '10:00', step: '00:15' },
非法与零步长: { start: '-01:00', end: 'not-a-time', step: '00:00' },
溢出: { start: '25:70', end: '26:40', step: '00:30' },
跨午夜: { start: '23:45', end: '24:15', step: '00:30' },
倒置范围: { start: '20:00', end: '10:00', step: '00:30' }
};
const scenario = ref<keyof typeof configurations>('正常');
const configuration = computed(() => configurations[scenario.value]);
const includeEndTime = ref(false);
const boundEnd = ref(false);
watch(scenario, () => {
value.value = null;
});
</script>
<style scoped>
.demo-layout-1 {
display: grid;
gap: var(--asam-space-md);
}
</style>
<template>
<section class="demo-layout-1">
<label for="ui028-scenario">配置场景</label>
<AsamSelect id="ui028-scenario" v-model="scenario">
<AsamOption
v-for="(config, name) in configurations"
:key="name"
:value="name"
:label="name"
>
{{ name }}
</AsamOption>
</AsamSelect>
<AsamCheckboxItem v-model="includeEndTime">包含终点</AsamCheckboxItem>
<AsamCheckboxItem v-model="boundEnd">minTime 等于 end</AsamCheckboxItem>
<!-- prettier-ignore -->
<AsamTimeSelect
v-model="value"
v-bind="configuration"
:min-time="boundEnd ? configuration.end : undefined"
:include-end-time="includeEndTime"
:teleported="false"
/>
<output>输入配置 {{ configuration }};显示格式 HH:mm;选择提交模型 {{ value }}</output>
</section>
</template>
<script setup>
defineOptions({ name: 'AsamTimeSelectinvalidconfigExample' });
import { computed, ref, watch } from 'vue';
import { AsamSelect, AsamOption, AsamCheckboxItem, AsamTimeSelect } from '@asam-ui/ui';
const value = ref(null);
const configurations = {
正常: { start: '09:00', end: '10:00', step: '00:15' },
非法与零步长: { start: '-01:00', end: 'not-a-time', step: '00:00' },
溢出: { start: '25:70', end: '26:40', step: '00:30' },
跨午夜: { start: '23:45', end: '24:15', step: '00:30' },
倒置范围: { start: '20:00', end: '10:00', step: '00:30' }
};
const scenario = ref('正常');
const configuration = computed(() => configurations[scenario.value]);
const includeEndTime = ref(false);
const boundEnd = ref(false);
watch(scenario, () => {
value.value = null;
});
</script>
<style scoped>
.demo-layout-1 {
display: grid;
gap: var(--asam-space-md);
}
</style>
本地化与高级配置 ​
通过 ConfigProvider 在中文和英文之间切换;该例使用明确公开类型配置本入口的高级属性。尺寸、模型、原生范围与两个独立端点的职责仍按前文分支生效。
日期语言和控件文字是两份配置:本例的 locale.ts / locale.js 同时注册 Day.js 的 zh-cn 日期 locale,中文每周从周一开始,英文从周日开始。 完整说明。
固定版本已经创建的日期对象可能保留旧 locale;本示例切换语言时通过 key 重建控件以更新日期语言,输入弹层会关闭,重新打开即可查看新语言。该例格式含本地化 AM/PM,切换语言时清空旧格式字符串;需要稳定的语言无关模型,可使用 HH:mm。
本地化与高级配置的完整 SFC
<!-- 此演示还使用 @asam-ui/icons-vue、dayjs,请按官网对应指南配置这些公开依赖。 -->
<template><StandaloneDemo /></template>
<script lang="ts" setup>
import * as __external0 from "vue";
import * as __external1 from "@asam-ui/ui";
import * as __external2 from "@asam-ui/icons-vue";
import * as __external3 from "dayjs";
import * as __external4 from "dayjs/locale/zh-cn.js";
const __external: any = {"vue": { ...__external0, __esModule: true },
"@asam-ui/ui": { ...__external1, __esModule: true },
"@asam-ui/icons-vue": { ...__external2, __esModule: true },
"dayjs": { ...__external3, __esModule: true },
"dayjs/locale/zh-cn.js": { ...__external4, __esModule: true }};
const __modules: any = {
"Demo.vue": (module: any, exports: any, require: any) => {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const vue_1: any = require("vue");
const vue_2: any = require("vue");
const _hoisted_1: any = { class: "demo-layout-1" };
const vue_3: any = require("vue");
const ui_1: any = require("@asam-ui/ui");
const locale_js_1: any = require("./locale.js");
const icons_vue_1: any = require("@asam-ui/icons-vue");
exports.default = (0, vue_1.defineComponent)({
...{ name: 'AsamTimeSelectAdvancedContractExample' },
__name: 'Demo',
setup(__props?: any) {
const chinese: any = (0, vue_3.ref)(true);
const disabled: any = (0, vue_3.ref)(false);
const changes: any = (0, vue_3.ref)(0);
const value: any = (0, vue_3.ref)(null);
(0, vue_3.watch)(chinese, () => {
value.value = null;
});
const configuration: any = {
start: '09:00',
end: '10:00',
step: '00:15',
format: 'hh:mm A',
includeEndTime: true,
minTime: '09:00',
maxTime: '10:00',
placeholder: '可选时间',
effect: 'dark',
teleported: false,
validateEvent: false,
clearable: true,
editable: true,
popperClass: 'advanced-time-popup',
popperStyle: { borderWidth: '2px' },
valueOnClear: '',
emptyValues: ['', null, undefined],
name: 'appointment',
prefixIcon: icons_vue_1.CaretLeft,
clearIcon: icons_vue_1.CaretRight
};
return (_ctx?: any, _cache?: any) => {
return ((0, vue_2.openBlock)(), (0, vue_2.createElementBlock)("section", _hoisted_1, [
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamCheckboxItem), {
modelValue: chinese.value,
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event?: any) => ((chinese).value = $event))
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[4] || (_cache[4] = [
(0, vue_2.createTextVNode)("中文本地化", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}, 8 /* PROPS */, ["modelValue"]),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamCheckboxItem), {
modelValue: disabled.value,
"onUpdate:modelValue": _cache[1] || (_cache[1] = ($event?: any) => ((disabled).value = $event))
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[5] || (_cache[5] = [
(0, vue_2.createTextVNode)("禁用", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}, 8 /* PROPS */, ["modelValue"]),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamConfigProvider), {
locale: chinese.value ? (0, vue_2.unref)(locale_js_1.zhCn) : (0, vue_2.unref)(locale_js_1.en)
}, {
default: (0, vue_2.withCtx)(() => [
((0, vue_2.openBlock)(), (0, vue_2.createBlock)((0, vue_2.unref)(ui_1.AsamTimeSelect), (0, vue_2.mergeProps)({
key: chinese.value ? 'zh-cn' : 'en',
modelValue: value.value,
"onUpdate:modelValue": _cache[2] || (_cache[2] = ($event?: any) => ((value).value = $event))
}, configuration, {
disabled: disabled.value,
onChange: _cache[3] || (_cache[3] = ($event?: any) => (changes.value++))
}), null, 16 /* FULL_PROPS */, ["modelValue", "disabled"]))
]),
_: 1 /* STABLE */
}, 8 /* PROPS */, ["locale"]),
(0, vue_2.createElementVNode)("output", null, "模型 " + (0, vue_2.toDisplayString)(value.value) + ";提交次数 " + (0, vue_2.toDisplayString)(changes.value), 1 /* TEXT */)
]));
};
}
});
exports.default.__scopeId = "data-v-3564f380";
},
"locale.ts": (module: any, exports: any, require: any) => {
"use strict";
var __importDefault: any = function (mod?: any) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.en = exports.zhCn = void 0;
const dayjs_1: any = __importDefault(require("dayjs"));
const zh_cn_js_1: any = __importDefault(require("dayjs/locale/zh-cn.js"));
// Register date locale on the same public Day.js instance used by the components.
// The third argument preserves the application default; the provider selects per component.
dayjs_1.default.locale(zh_cn_js_1.default, undefined, true);
/** Application-authored dictionary, supplied through the public provider. */
exports.zhCn = {
name: 'zh-cn',
el: {
datepicker: {
now: '当前时刻',
today: '当前日期',
cancel: '取消选择',
clear: '清除选择',
confirm: '应用选择',
dateTablePrompt: '方向键选日期,回车确认',
monthTablePrompt: '方向键选月份',
quarterTablePrompt: '方向键选季度',
yearTablePrompt: '方向键选年份',
selectedDate: '当前选择',
selectDate: '选择日期',
selectTime: '选择时间',
startDate: '起始日期',
startTime: '起始时间',
endDate: '结束日期',
endTime: '结束时间',
prevYear: '上一年',
nextYear: '下一年',
prevMonth: '上一月',
nextMonth: '下一月',
year: '年',
...Object.fromEntries(Array.from({ length: 12 }, (_?: any, index?: any) => ['month' + (index + 1), index + 1 + '月'])),
weeks: {
sun: '周日',
mon: '周一',
tue: '周二',
wed: '周三',
thu: '周四',
fri: '周五',
sat: '周六'
},
months: {
jan: '一月',
feb: '二月',
mar: '三月',
apr: '四月',
may: '五月',
jun: '六月',
jul: '七月',
aug: '八月',
sep: '九月',
oct: '十月',
nov: '十一月',
dec: '十二月'
},
quarters: { q1: '第一季度', q2: '第二季度', q3: '第三季度', q4: '第四季度' }
},
calendar: { prevMonth: '上一月', nextMonth: '下一月', today: '当前日期' },
select: {
loading: '正在读取',
noMatch: '没有匹配时间',
noData: '没有可选时间',
placeholder: '选择时间'
}
}
};
exports.en = {
name: 'en',
el: {
datepicker: {
...exports.zhCn.el.datepicker,
now: 'Now',
today: 'Today',
cancel: 'Cancel',
clear: 'Clear',
confirm: 'OK',
dateTablePrompt: 'Use arrows to select a date',
monthTablePrompt: 'Use arrows to select a month',
quarterTablePrompt: 'Use arrows to select a quarter',
yearTablePrompt: 'Use arrows to select a year',
selectedDate: 'Selected date',
selectDate: 'Select date',
selectTime: 'Select time',
startDate: 'Start date',
startTime: 'Start time',
endDate: 'End date',
endTime: 'End time',
prevYear: 'Previous year',
nextYear: 'Next year',
prevMonth: 'Previous month',
nextMonth: 'Next month',
year: '',
...Object.fromEntries([
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December'
].map((month?: any, index?: any) => ['month' + (index + 1), month])),
weeks: {
sun: 'Sun',
mon: 'Mon',
tue: 'Tue',
wed: 'Wed',
thu: 'Thu',
fri: 'Fri',
sat: 'Sat'
},
months: {
jan: 'Jan',
feb: 'Feb',
mar: 'Mar',
apr: 'Apr',
may: 'May',
jun: 'Jun',
jul: 'Jul',
aug: 'Aug',
sep: 'Sep',
oct: 'Oct',
nov: 'Nov',
dec: 'Dec'
},
quarters: { q1: 'Q1', q2: 'Q2', q3: 'Q3', q4: 'Q4' }
},
calendar: { prevMonth: 'Previous month', nextMonth: 'Next month', today: 'Today' },
select: {
loading: 'Loading times',
noMatch: 'No matching time',
noData: 'No available time',
placeholder: 'Select a time'
}
}
};
},
};
const __dependencies: any = {"Demo.vue":{"./locale.js":"locale.ts"},"locale.ts":{}};
const __cache: any = Object.create(null);
function __require(id: any): any {
if (__external[id]) return __external[id];
if (__cache[id]) return __cache[id].exports;
const module: any = { exports: {} };
__cache[id] = module;
__modules[id](module, module.exports, (dependency: any) => __require(__dependencies[id][dependency] || dependency));
return module.exports;
}
const StandaloneDemo = __require('Demo.vue').default;
</script>
<style>
.demo-layout-1[data-v-3564f380] {
display: grid;
gap: var(--asam-space-md);
}
</style>
<!-- 此演示还使用 @asam-ui/icons-vue、dayjs,请按官网对应指南配置这些公开依赖。 -->
<template><StandaloneDemo /></template>
<script setup>
import * as __external0 from "vue";
import * as __external1 from "@asam-ui/ui";
import * as __external2 from "@asam-ui/icons-vue";
import * as __external3 from "dayjs";
import * as __external4 from "dayjs/locale/zh-cn.js";
const __external = {"vue": { ...__external0, __esModule: true },
"@asam-ui/ui": { ...__external1, __esModule: true },
"@asam-ui/icons-vue": { ...__external2, __esModule: true },
"dayjs": { ...__external3, __esModule: true },
"dayjs/locale/zh-cn.js": { ...__external4, __esModule: true }};
const __modules = {
"Demo.vue": (module, exports, require) => {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const vue_1 = require("vue");
const _hoisted_1 = { class: "demo-layout-1" };
const vue_2 = require("vue");
const ui_1 = require("@asam-ui/ui");
const locale_js_1 = require("./locale.js");
const icons_vue_1 = require("@asam-ui/icons-vue");
exports.default = Object.assign({ name: 'AsamTimeSelectAdvancedContractExample' }, {
__name: 'Demo',
setup(__props) {
const chinese = (0, vue_2.ref)(true);
const disabled = (0, vue_2.ref)(false);
const changes = (0, vue_2.ref)(0);
const value = (0, vue_2.ref)(null);
(0, vue_2.watch)(chinese, () => {
value.value = null;
});
const configuration = {
start: '09:00',
end: '10:00',
step: '00:15',
format: 'hh:mm A',
includeEndTime: true,
minTime: '09:00',
maxTime: '10:00',
placeholder: '可选时间',
effect: 'dark',
teleported: false,
validateEvent: false,
clearable: true,
editable: true,
popperClass: 'advanced-time-popup',
popperStyle: { borderWidth: '2px' },
valueOnClear: '',
emptyValues: ['', null, undefined],
name: 'appointment',
prefixIcon: icons_vue_1.CaretLeft,
clearIcon: icons_vue_1.CaretRight
};
return (_ctx, _cache) => {
return ((0, vue_1.openBlock)(), (0, vue_1.createElementBlock)("section", _hoisted_1, [
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamCheckboxItem), {
modelValue: chinese.value,
"onUpdate:modelValue": _cache[0] || (_cache[0] = $event => ((chinese).value = $event))
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[4] || (_cache[4] = [
(0, vue_1.createTextVNode)("中文本地化", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}, 8 /* PROPS */, ["modelValue"]),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamCheckboxItem), {
modelValue: disabled.value,
"onUpdate:modelValue": _cache[1] || (_cache[1] = $event => ((disabled).value = $event))
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[5] || (_cache[5] = [
(0, vue_1.createTextVNode)("禁用", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}, 8 /* PROPS */, ["modelValue"]),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamConfigProvider), {
locale: chinese.value ? (0, vue_1.unref)(locale_js_1.zhCn) : (0, vue_1.unref)(locale_js_1.en)
}, {
default: (0, vue_1.withCtx)(() => [
((0, vue_1.openBlock)(), (0, vue_1.createBlock)((0, vue_1.unref)(ui_1.AsamTimeSelect), (0, vue_1.mergeProps)({
key: chinese.value ? 'zh-cn' : 'en',
modelValue: value.value,
"onUpdate:modelValue": _cache[2] || (_cache[2] = $event => ((value).value = $event))
}, configuration, {
disabled: disabled.value,
onChange: _cache[3] || (_cache[3] = $event => (changes.value++))
}), null, 16 /* FULL_PROPS */, ["modelValue", "disabled"]))
]),
_: 1 /* STABLE */
}, 8 /* PROPS */, ["locale"]),
(0, vue_1.createElementVNode)("output", null, "模型 " + (0, vue_1.toDisplayString)(value.value) + ";提交次数 " + (0, vue_1.toDisplayString)(changes.value), 1 /* TEXT */)
]));
};
}
});
exports.default.__scopeId = "data-v-e4b47708";
},
"locale.js": (module, exports, require) => {
"use strict";
var __importDefault = function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.en = exports.zhCn = void 0;
const dayjs_1 = __importDefault(require("dayjs"));
const zh_cn_js_1 = __importDefault(require("dayjs/locale/zh-cn.js"));
// Register date locale on the same public Day.js instance used by the components.
// The third argument preserves the application default; the provider selects per component.
dayjs_1.default.locale(zh_cn_js_1.default, undefined, true);
/** Application-authored dictionary, supplied through the public provider. */
exports.zhCn = {
name: 'zh-cn',
el: {
datepicker: {
now: '当前时刻',
today: '当前日期',
cancel: '取消选择',
clear: '清除选择',
confirm: '应用选择',
dateTablePrompt: '方向键选日期,回车确认',
monthTablePrompt: '方向键选月份',
quarterTablePrompt: '方向键选季度',
yearTablePrompt: '方向键选年份',
selectedDate: '当前选择',
selectDate: '选择日期',
selectTime: '选择时间',
startDate: '起始日期',
startTime: '起始时间',
endDate: '结束日期',
endTime: '结束时间',
prevYear: '上一年',
nextYear: '下一年',
prevMonth: '上一月',
nextMonth: '下一月',
year: '年',
...Object.fromEntries(Array.from({ length: 12 }, (_, index) => ['month' + (index + 1), index + 1 + '月'])),
weeks: {
sun: '周日',
mon: '周一',
tue: '周二',
wed: '周三',
thu: '周四',
fri: '周五',
sat: '周六'
},
months: {
jan: '一月',
feb: '二月',
mar: '三月',
apr: '四月',
may: '五月',
jun: '六月',
jul: '七月',
aug: '八月',
sep: '九月',
oct: '十月',
nov: '十一月',
dec: '十二月'
},
quarters: { q1: '第一季度', q2: '第二季度', q3: '第三季度', q4: '第四季度' }
},
calendar: { prevMonth: '上一月', nextMonth: '下一月', today: '当前日期' },
select: {
loading: '正在读取',
noMatch: '没有匹配时间',
noData: '没有可选时间',
placeholder: '选择时间'
}
}
};
exports.en = {
name: 'en',
el: {
datepicker: {
...exports.zhCn.el.datepicker,
now: 'Now',
today: 'Today',
cancel: 'Cancel',
clear: 'Clear',
confirm: 'OK',
dateTablePrompt: 'Use arrows to select a date',
monthTablePrompt: 'Use arrows to select a month',
quarterTablePrompt: 'Use arrows to select a quarter',
yearTablePrompt: 'Use arrows to select a year',
selectedDate: 'Selected date',
selectDate: 'Select date',
selectTime: 'Select time',
startDate: 'Start date',
startTime: 'Start time',
endDate: 'End date',
endTime: 'End time',
prevYear: 'Previous year',
nextYear: 'Next year',
prevMonth: 'Previous month',
nextMonth: 'Next month',
year: '',
...Object.fromEntries([
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December'
].map((month, index) => ['month' + (index + 1), month])),
weeks: {
sun: 'Sun',
mon: 'Mon',
tue: 'Tue',
wed: 'Wed',
thu: 'Thu',
fri: 'Fri',
sat: 'Sat'
},
months: {
jan: 'Jan',
feb: 'Feb',
mar: 'Mar',
apr: 'Apr',
may: 'May',
jun: 'Jun',
jul: 'Jul',
aug: 'Aug',
sep: 'Sep',
oct: 'Oct',
nov: 'Nov',
dec: 'Dec'
},
quarters: { q1: 'Q1', q2: 'Q2', q3: 'Q3', q4: 'Q4' }
},
calendar: { prevMonth: 'Previous month', nextMonth: 'Next month', today: 'Today' },
select: {
loading: 'Loading times',
noMatch: 'No matching time',
noData: 'No available time',
placeholder: 'Select a time'
}
}
};
},
};
const __dependencies = {"Demo.vue":{"./locale.js":"locale.js"},"locale.js":{}};
const __cache = Object.create(null);
function __require(id) {
if (__external[id]) return __external[id];
if (__cache[id]) return __cache[id].exports;
const module = { exports: {} };
__cache[id] = module;
__modules[id](module, module.exports, (dependency) => __require(__dependencies[id][dependency] || dependency));
return module.exports;
}
const StandaloneDemo = __require('Demo.vue').default;
</script>
<style>
.demo-layout-1[data-v-e4b47708] {
display: grid;
gap: var(--asam-space-md);
}
</style>
原生清空配置与迁移 ​
基础入口仅委托原生公开 props、事件、slots、模型与 expose。未传属性与显式 undefined、null、false 均保持原生语义;不补入空值,不替换清空工厂,不将输出统一为 null。合法 0、false、undefined 或数组工厂输出及原生的事件顺序完整保留,工厂调用受原生校验与计算规则约束。
固定 2.14.7 对某些清空哨兵与格式组合可能产生空显示、格式化异常或诊断;这些属于原生兼容限制,基础包装不接管处理。 完整说明。
清空工厂与上下文配置
<template>
<section class="demo-layout-1">
<label>
<!-- Change the public configuration without recreating controls. -->
<span>配置位置</span>
<AsamSelect v-model="scope">
<AsamOption value="props" :label="'当前控件'">当前控件</AsamOption>
<AsamOption value="provider" :label="'ConfigProvider'">ConfigProvider</AsamOption>
</AsamSelect></label
>
<label>
<!-- Change the public configuration without recreating controls. -->
<span>清空值</span>
<AsamSelect v-model="mode">
<AsamOption value="array" :label="'空数组'">空数组</AsamOption>
<AsamOption value="nulls" :label="'两个 null'">两个 null</AsamOption>
<AsamOption value="undefineds" :label="'两个 undefined'">两个 undefined</AsamOption>
<AsamOption value="null" :label="'null'">null</AsamOption>
</AsamSelect></label
>
<AsamConfigProvider v-bind="scope === 'provider' ? configuration : {}">
<AsamTimeSelect
v-model="value"
v-bind="scope === 'props' ? configuration : {}"
start="09:00"
end="11:00"
step="00:30"
@change="changes++"
@clear="clears++"
/>
</AsamConfigProvider>
<AsamButton type="default" native-type="button" @click="value = '09:30'"
>回填时间</AsamButton
>
<AsamButton type="default" native-type="button" @click="observeFactory"
>读取工厂调用次数</AsamButton
>
<output>{{ summary }}</output>
</section>
</template>
<script lang="ts" setup>
import { computed, ref } from 'vue';
import {
AsamSelect,
AsamOption,
AsamButton,
AsamConfigProvider,
AsamTimeSelect
} from '@asam-ui/ui';
import type { AsamTimeSelectValue, AsamTimeSelectProps } from '@asam-ui/ui';
defineOptions({ name: 'AsamTimeSelectEmptyValuesExample' });
const scope = ref('props');
const mode = ref('array');
const value = ref<AsamTimeSelectValue>('09:30');
const changes = ref(0);
const clears = ref(0);
const observedCalls = ref(0);
const summary = computed(
() =>
'模型 ' +
JSON.stringify(value.value) +
';change ' +
changes.value +
';clear ' +
clears.value +
';工厂 ' +
observedCalls.value
);
let factoryCalls = 0;
function observeFactory() {
observedCalls.value = factoryCalls;
}
function clearFactory() {
factoryCalls++;
return mode.value === 'array'
? []
: mode.value === 'nulls'
? [null, null]
: mode.value === 'undefineds'
? [undefined, undefined]
: null;
}
const configuration = computed<Pick<AsamTimeSelectProps, 'emptyValues' | 'valueOnClear'>>(() => ({
emptyValues: ['', null, undefined, [], [null, null], [undefined, undefined]],
valueOnClear: clearFactory
}));
</script>
<style scoped>
.demo-layout-1 {
display: grid;
gap: var(--asam-space-md);
}
</style>
<template>
<section class="demo-layout-1">
<label>
<!-- Change the public configuration without recreating controls. -->
<span>配置位置</span>
<AsamSelect v-model="scope">
<AsamOption value="props" :label="'当前控件'">当前控件</AsamOption>
<AsamOption value="provider" :label="'ConfigProvider'">ConfigProvider</AsamOption>
</AsamSelect></label
>
<label>
<!-- Change the public configuration without recreating controls. -->
<span>清空值</span>
<AsamSelect v-model="mode">
<AsamOption value="array" :label="'空数组'">空数组</AsamOption>
<AsamOption value="nulls" :label="'两个 null'">两个 null</AsamOption>
<AsamOption value="undefineds" :label="'两个 undefined'">两个 undefined</AsamOption>
<AsamOption value="null" :label="'null'">null</AsamOption>
</AsamSelect></label
>
<AsamConfigProvider v-bind="scope === 'provider' ? configuration : {}">
<AsamTimeSelect
v-model="value"
v-bind="scope === 'props' ? configuration : {}"
start="09:00"
end="11:00"
step="00:30"
@change="changes++"
@clear="clears++"
/>
</AsamConfigProvider>
<AsamButton type="default" native-type="button" @click="value = '09:30'"
>回填时间</AsamButton
>
<AsamButton type="default" native-type="button" @click="observeFactory"
>读取工厂调用次数</AsamButton
>
<output>{{ summary }}</output>
</section>
</template>
<script setup>
import { computed, ref } from 'vue';
import {
AsamSelect,
AsamOption,
AsamButton,
AsamConfigProvider,
AsamTimeSelect
} from '@asam-ui/ui';
defineOptions({ name: 'AsamTimeSelectEmptyValuesExample' });
const scope = ref('props');
const mode = ref('array');
const value = ref('09:30');
const changes = ref(0);
const clears = ref(0);
const observedCalls = ref(0);
const summary = computed(
() =>
'模型 ' +
JSON.stringify(value.value) +
';change ' +
changes.value +
';clear ' +
clears.value +
';工厂 ' +
observedCalls.value
);
let factoryCalls = 0;
function observeFactory() {
observedCalls.value = factoryCalls;
}
function clearFactory() {
factoryCalls++;
return mode.value === 'array'
? []
: mode.value === 'nulls'
? [null, null]
: mode.value === 'undefineds'
? [undefined, undefined]
: null;
}
const configuration = computed(() => ({
emptyValues: ['', null, undefined, [], [null, null], [undefined, undefined]],
valueOnClear: clearFactory
}));
</script>
<style scoped>
.demo-layout-1 {
display: grid;
gap: var(--asam-space-md);
}
</style>
原生默认值与适配说明 ​
start=09:00、end=18:00、step=00:30、format=HH:mm;modelValue 未设置时为 undefined。 完整说明。
局部与全局浮层 ​
基础示例使用默认的全局挂载;局部挂载示例展示显式配置的 teleported 或 appendTo。先打开控件浮层,再观察其所在容器。挂载位置与控件值、请求协议互相独立。
API
属性 AsamTimeSelectProps
| 属性名 | 说明 | 类型 | 默认值 |
|---|---|---|---|
effect | Tooltip 主题,内置了 dark / light 两种 | enum"light" | "dark"完整类型:(AsamTimeSelectProps)["effect"] | — |
popperClass | 为 TimeSelect 下拉面板设置自定义类名 | AsamTimeSelectProps["popperClass"] | — |
popperStyle | 为 TimeSelect 下拉面板设置自定义样式 | (AsamTimeSelectProps)["popperStyle"] | — |
disabled | 禁用状态 | (AsamTimeSelectProps)["disabled"] | false |
start | 开始时间 | string | undefined | — |
name | 原生属性 | string | undefined | — |
format | 设置时间格式 | string | undefined | — |
end | 结束时间 | string | undefined | — |
editable | 文本框可输入 | (AsamTimeSelectProps)["editable"] | false |
emptyValues | 组件空值配置,参阅配置提供器的空值说明。 | unknown[] | undefined | — |
valueOnClear | 清空后的返回值,参阅配置提供器的空值说明。 | (AsamTimeSelectProps)["valueOnClear"] | — |
clearable | 是否显示清除按钮 | (AsamTimeSelectProps)["clearable"] | false |
step | 间隔时间 | string | undefined | — |
clearIcon | 自定义清除图标 | (AsamTimeSelectProps)["clearIcon"] | — |
prefixIcon | 自定义前缀图标 | (AsamTimeSelectProps)["prefixIcon"] | — |
placeholder | 非范围选择时的占位内容 | string | undefined | — |
minTime | 最早时间点,早于该时间的时间段将被禁用 | (AsamTimeSelectProps)["minTime"] | — |
maxTime | 最晚时间点,晚于该时间的时间段将被禁用 | (AsamTimeSelectProps)["maxTime"] | — |
includeEndTime | 是否在选项中包含end | boolean | undefined | false |
size | 输入框尺寸 | enum"large" | "big" | "default" | "small"完整类型:AsamControlSize | undefined | — |
modelValue | 选中项绑定值 | AsamTimeSelectValue | false |
teleported | 透传给内部选择器浮层。 | boolean | undefined | false |
validateEvent | 透传给内部选择器的表单校验契约。 | boolean | undefined | false |
事件 AsamTimeSelectEmits
| 属性名 | 说明 | 类型 | 默认值 |
|---|---|---|---|
update:modelValue | — | [value: AsamTimeSelectValue] | — |
change | — | [value: AsamTimeSelectValue] | — |
focus | — | [event: FocusEvent] | — |
blur | — | [event: FocusEvent] | — |
clear | — | (AsamTimeSelectEmits)["clear"] | — |
插槽 AsamTimeSelectSlots
实例方法与状态 AsamTimeSelectExpose
| 属性名 | 说明 | 类型 | 默认值 |
|---|---|---|---|
focus | 使选择器的输入框获取焦点 | () => void | — |
blur | 使 input 失去焦点 | () => void | — |
用法与契约补充说明 ​
ASAM 扩展与迁移 ​
固定 2.14.7 对无法解析或负数的 start/end,以及无法解析、负数或零步长 step 给出诊断,并分别回退到 09:00、18:00、00:30,避免无穷生成选项。原生没有附加 24 小时或 60 分钟上限:25:70 的解析和内部格式仍为 25:70;推进零步长得到 26:10,推进 00:30 得到 26:40(组件中的零步长先回退,不能用工具函数零步长代替组件行为)。默认 HH:mm 下对应选项显示 02:10 和 02:40,选择时模型也是这个显示格式值;跨午夜的 24:15 同样显示并提交 00:15。需要限制钟表范围时,由调用方验证输入。
ASAM 扩展与迁移 ​
start 大于 end 且 includeEndTime=false 时没有选项;includeEndTime=true 时仍追加 end。minTime/maxTime 使用原始时间比较,等于 min/max 的选项也禁用,包括被追加的 end。format 同时决定选项显示和选择提交的文本;不自动清除调用方已有的越界模型,联动更新由调用方决定。teleported 和 validateEvent 由内部 Select 承接。
ASAM 扩展与迁移 ​
ASAM 四档 size 与表单、ConfigProvider 继承一致。step 是时间文本,不是分钟数。 validateEvent 控制表单校验触发;teleported 决定弹层挂载位置。 单点日期时间使用 DatePicker type=datetime;两个独立日期时间端点使用 DateTimeRangePicker。
本地化与高级配置 ​
日期语言和控件文字是两份配置:本例的 locale.ts / locale.js 同时注册 Day.js 的 zh-cn 日期 locale,中文每周从周一开始,英文从周日开始。应用需显式安装 dayjs,并保证组件与应用消费同一实例;只切换 Provider 字典不会改变周首日。日期 locale 注册不切换应用的全局默认语言。
原生清空配置与迁移 ​
固定 2.14.7 对某些清空哨兵与格式组合可能产生空显示、格式化异常或诊断;这些属于原生兼容限制,基础包装不接管处理。需要 nullable 业务模型的调用方应在自己的高级数据适配层处理;双端 DateTimeRangePicker/DateTimePicker 保留明确的完整范围/null 组合协议。原依赖默认字符串模型的用法需显式传入 valueFormat(日期 YYYY-MM-DD,时间 HH:mm:ss)。
原生默认值与适配说明 ​
start=09:00、end=18:00、step=00:30、format=HH:mm;modelValue 未设置时为 undefined。 其余行为默认值交由固定版本原生组件解析;显式 undefined、null、false 原样输入,不以包装层默认值覆盖。size 仅负责 ASAM large/big/default/small 四档密度及品牌样式。DatePicker/TimePicker/TimeSelect 的 focus/blur(日期和时间另有 handleOpen/handleClose)直接使用原生公开实例的接收者和返回值;Panel 没有这些输入实例方法。
关联组件
参数与事件补充说明
完整透传 2.14.7 的基础参数,并在适用时使用 ASAM 尺寸密度。
参数与事件说明
effect
必填:否;声明来源:上游声明。
effect 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:"light" / "dark"
默认值与来源
未知 / 未声明固定上游文档默认:light(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:'light'(2.14.7;源码事实,未作为 ASAM 运行实测)
popperClass
必填:否;声明来源:上游声明。
popperClass 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false
默认值与来源
未知 / 未声明固定上游文档默认:''(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:''(2.14.7;源码事实,未作为 ASAM 运行实测)
popperStyle
必填:否;声明来源:上游声明。
popperStyle 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false
嵌套展开边界:框架 / 平台类型;完整类型见公开类型视图。
默认值与来源
未知 / 未声明固定上游文档默认:未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:undefined(2.14.7;源码事实,未作为 ASAM 运行实测)
disabled
必填:否;声明来源:上游声明。
disabled 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
默认值与来源
false(隐式 Boolean 默认;已安装组件)固定上游文档默认:false(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:undefined(2.14.7;源码事实,未作为 ASAM 运行实测)
start
必填:否;声明来源:上游声明。
默认值与来源
未知 / 未声明固定上游文档默认:09:00(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:DEFAULT_START(2.14.7;源码事实,未作为 ASAM 运行实测)
name
必填:否;声明来源:上游声明。
默认值与来源
未知 / 未声明固定上游文档默认:未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
format
必填:否;声明来源:上游声明。
默认值与来源
未知 / 未声明固定上游文档默认:HH:mm(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:'HH:mm'(2.14.7;源码事实,未作为 ASAM 运行实测)
end
必填:否;声明来源:上游声明。
默认值与来源
未知 / 未声明固定上游文档默认:18:00(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:DEFAULT_END(2.14.7;源码事实,未作为 ASAM 运行实测)
editable
必填:否;声明来源:上游声明。
editable 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
默认值与来源
false(隐式 Boolean 默认;已安装组件)固定上游文档默认:true(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:true(2.14.7;源码事实,未作为 ASAM 运行实测)
emptyValues
必填:否;声明来源:上游声明。
默认值与来源
未知 / 未声明固定上游文档默认:未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
valueOnClear
必填:否;声明来源:上游声明。
valueOnClear 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
valueOnClear.apply:(this: Function, thisArg: any, argArray?: any) => any— 依赖声明调用函数,以指定对象作为 this,并使用指定数组作为函数参数。
事件参数:
(this: Function, thisArg: any, argArray?: any): any嵌套展开边界:框架 / 平台类型;完整类型见公开类型视图。
valueOnClear.call:(this: Function, thisArg: any, ...argArray: any[]) => any— 依赖声明调用对象方法,并以另一个对象作为当前 this。
事件参数:
(this: Function, thisArg: any, ...argArray: any[]): any嵌套展开边界:框架 / 平台类型;完整类型见公开类型视图。
valueOnClear.bind:(this: Function, thisArg: any, ...argArray: any[]) => any— 依赖声明创建具有相同函数体的绑定函数,将 this 绑定到指定对象,并设置初始参数。
事件参数:
(this: Function, thisArg: any, ...argArray: any[]): any嵌套展开边界:框架 / 平台类型;完整类型见公开类型视图。
valueOnClear.toString:() => string— 依赖声明返回函数的字符串表示。
事件参数:
(): string嵌套展开边界:框架 / 平台类型;完整类型见公开类型视图。
valueOnClear.prototype:any— 依赖声明valueOnClear.length:number— 依赖声明valueOnClear.arguments:any— 依赖声明valueOnClear.caller:Function— 依赖声明嵌套展开边界:框架 / 平台类型;完整类型见公开类型视图。
valueOnClear.name:string— 依赖声明返回函数名称;函数名称只读,不能修改。
valueOnClear.__@hasInstance@8888:(value: any) => boolean— 依赖声明当函数用作构造函数时,判断指定值是否继承自该函数;构造函数可以覆盖此方法,控制 instanceof 对实例的识别。
事件参数:
(value: any): boolean嵌套展开边界:框架 / 平台类型;完整类型见公开类型视图。
默认值与来源
未知 / 未声明固定上游文档默认:未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
clearable
必填:否;声明来源:上游声明。
clearable 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
默认值与来源
false(隐式 Boolean 默认;已安装组件)固定上游文档默认:true(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:true(2.14.7;源码事实,未作为 ASAM 运行实测)
step
必填:否;声明来源:上游声明。
默认值与来源
未知 / 未声明固定上游文档默认:00:30(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:DEFAULT_STEP(2.14.7;源码事实,未作为 ASAM 运行实测)
clearIcon
必填:否;声明来源:上游声明。
clearIcon 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(props: any, ctx: Parameters<Extract<NonNullable<(AsamTimeSelectProps)["clearIcon"]>, (...args: never[]) => unknown>>[1]): any
clearIcon.__isFragment:undefined— 依赖声明clearIcon.__isTeleport:undefined— 依赖声明clearIcon.__isSuspense:undefined— 依赖声明
默认值与来源
未知 / 未声明固定上游文档默认:CircleClose(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码工厂(未执行):() => CircleClose(2.14.7;源码事实,未作为 ASAM 运行实测)
prefixIcon
必填:否;声明来源:上游声明。
prefixIcon 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(props: any, ctx: Parameters<Extract<NonNullable<(AsamTimeSelectProps)["prefixIcon"]>, (...args: never[]) => unknown>>[1]): any
prefixIcon.__isFragment:undefined— 依赖声明prefixIcon.__isTeleport:undefined— 依赖声明prefixIcon.__isSuspense:undefined— 依赖声明
默认值与来源
未知 / 未声明固定上游文档默认:Clock(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码工厂(未执行):() => Clock(2.14.7;源码事实,未作为 ASAM 运行实测)
placeholder
必填:否;声明来源:上游声明。
默认值与来源
未知 / 未声明固定上游文档默认:未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
minTime
必填:否;声明来源:上游声明。
默认值与来源
未知 / 未声明固定上游文档默认:未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码未声明 default(2.14.7;源码事实,未作为 ASAM 运行实测)
maxTime
必填:否;声明来源:上游声明。
默认值与来源
未知 / 未声明固定上游文档默认:未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码未声明 default(2.14.7;源码事实,未作为 ASAM 运行实测)
includeEndTime
必填:否;声明来源:上游声明。
includeEndTime 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
默认值与来源
false(隐式 Boolean 默认;已安装组件)固定上游文档默认:false(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
size
必填:否;声明来源:ASAM 声明。
size 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:"large" / "big" / "default" / "small"
modelValue
必填:否;声明来源:ASAM 声明。
modelValue 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
默认值与来源
false(隐式 Boolean 默认;已安装组件)teleported
必填:否;声明来源:ASAM 声明。
teleported 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
默认值与来源
false(隐式 Boolean 默认;已安装组件)validateEvent
必填:否;声明来源:ASAM 声明。
validateEvent 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
默认值与来源
false(隐式 Boolean 默认;已安装组件)AsamTimeSelectProps 公开类型视图
import type { Component, Attrs } from 'vue';
import type { AsamTimeSelectProps, AsamControlSize, AsamTimeSelectValue } from '@asam-ui/ui';
type PublicMember<T, K extends PropertyKey> = T extends unknown ? K extends keyof T ? T[K] : never : never;
// AsamTimeSelectProps
type PublicContract = {
readonly "effect"?: (AsamTimeSelectProps)["effect"];
readonly "popperClass"?: AsamTimeSelectProps["popperClass"];
readonly "popperStyle"?: (AsamTimeSelectProps)["popperStyle"];
readonly "disabled"?: (AsamTimeSelectProps)["disabled"];
readonly "start"?: string | undefined;
readonly "name"?: string | undefined;
readonly "format"?: string | undefined;
readonly "end"?: string | undefined;
readonly "editable"?: (AsamTimeSelectProps)["editable"];
readonly "emptyValues"?: unknown[] | undefined;
readonly "valueOnClear"?: (AsamTimeSelectProps)["valueOnClear"];
readonly "clearable"?: (AsamTimeSelectProps)["clearable"];
readonly "step"?: string | undefined;
readonly "clearIcon"?: (AsamTimeSelectProps)["clearIcon"];
readonly "prefixIcon"?: (AsamTimeSelectProps)["prefixIcon"];
readonly "placeholder"?: string | undefined;
readonly "minTime"?: (AsamTimeSelectProps)["minTime"];
readonly "maxTime"?: (AsamTimeSelectProps)["maxTime"];
readonly "includeEndTime"?: boolean | undefined;
"size"?: AsamControlSize | undefined;
"modelValue"?: AsamTimeSelectValue;
"teleported"?: boolean | undefined;
"validateEvent"?: boolean | undefined;
};
参数与事件说明
update:modelValue
必填:是;声明来源:ASAM 声明。
change
必填:是;声明来源:ASAM 声明。
focus
必填:是;声明来源:ASAM 声明。
blur
必填:是;声明来源:ASAM 声明。
clear
必填:是;声明来源:ASAM 声明。
AsamTimeSelectEmits 公开类型视图
import type { AsamTimeSelectEmits, AsamTimeSelectValue } from '@asam-ui/ui';
// AsamTimeSelectEmits
type PublicContract = {
"update:modelValue": [value: AsamTimeSelectValue];
"change": [value: AsamTimeSelectValue];
"focus": [event: FocusEvent];
"blur": [event: FocusEvent];
"clear": (AsamTimeSelectEmits)["clear"];
};
AsamTimeSelectSlots 公开类型视图
import type { AsamTimeSelectSlots } from '@asam-ui/ui';
// AsamTimeSelectSlots
type PublicContract = {
[key: string]: never;
};
参数与事件说明
focus
必填:是;声明来源:上游声明。
focus 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(): void
blur
必填:是;声明来源:上游声明。
blur 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(): void
AsamTimeSelectExpose 公开类型视图
import type { AsamTimeSelectExpose } from '@asam-ui/ui';
// AsamTimeSelectExpose
type PublicContract = {
"focus": () => void;
"blur": () => void;
};