使用场景 ​
用于地址、名称等允许自由输入的补全。ASAM options 模式按 label 过滤并忽略禁用选项,选中时返回原 option 对象。模型保存显示文本;需要固定选项值模型时使用 Select。
ASAM 静态选项 ​
maxSuggestions 默认 100,必须是正整数;仅限制 ASAM options/数据桥接建议。匹配选择的 select 返回原选项,包含业务 value、label、raw 及扩展字段,保持对象 identity。建议数组、默认插槽与 handleSelect 仍只接受完整候选。
ASAM 静态选项
<template>
<div class="example">
<AsamAutocomplete
v-model="value"
v-bind="{ class: 'field', 'aria-label': '城市补全' }"
:options="options"
:max-suggestions="3"
clearable
@select="(item) => (selected = JSON.stringify(item))"
/>
<output>文本:{{ value }};选项:{{ selected }}</output>
</div>
</template>
<script lang="ts" setup>
defineOptions({ name: 'AsamAutocompleteOptionsExample' });
import { ref } from 'vue';
import { AsamAutocomplete } from '@asam-ui/ui';
import type { AsamOption } from '@asam-ui/ui';
const value = ref('');
const selected = ref('尚未选择');
const options: AsamOption<string>[] = [
{ value: 'shanghai', label: '上海', raw: { code: 'SH' } },
{ value: 'beijing', label: '北京', raw: { code: 'BJ' } },
{ value: 'closed', label: '停用城市', disabled: true, raw: { code: 'OFF' } }
];
</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);
}
.field {
width: 100%;
max-width: 360px;
}
output {
overflow-wrap: anywhere;
color: var(--asam-color-text-secondary);
}
</style>
<template>
<div class="example">
<AsamAutocomplete
v-model="value"
v-bind="{ class: 'field', 'aria-label': '城市补全' }"
:options="options"
:max-suggestions="3"
clearable
@select="(item) => (selected = JSON.stringify(item))"
/>
<output>文本:{{ value }};选项:{{ selected }}</output>
</div>
</template>
<script setup>
defineOptions({ name: 'AsamAutocompleteOptionsExample' });
import { ref } from 'vue';
import { AsamAutocomplete } from '@asam-ui/ui';
const value = ref('');
const selected = ref('尚未选择');
const options = [
{ value: 'shanghai', label: '上海', raw: { code: 'SH' } },
{ value: 'beijing', label: '北京', raw: { code: 'BJ' } },
{ value: 'closed', label: '停用城市', disabled: true, raw: { code: 'OFF' } }
];
</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);
}
.field {
width: 100%;
max-width: 360px;
}
output {
overflow-wrap: anywhere;
color: var(--asam-color-text-secondary);
}
</style>
函数建议与多文件数据 ​
fetchSuggestions 优先于 options,支持数组、callback 或返回数组的 Promise。valueKey 指定建议的显示字段;原函数建议不会被 maxSuggestions 截断。
函数建议与多文件数据
<template><StandaloneDemo /></template>
<script lang="ts" setup>
import * as __external0 from "vue";
import * as __external1 from "@asam-ui/ui";
const __external: any = {"vue": { ...__external0, __esModule: true },
"@asam-ui/ui": { ...__external1, __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: "example" };
const vue_3: any = require("vue");
const ui_1: any = require("@asam-ui/ui");
const suggestions_1: any = require("./suggestions");
exports.default = (0, vue_1.defineComponent)({
...{ name: 'AsamAutocompleteSuggestionsExample' },
__name: 'Demo',
setup(__props?: any) {
const value: any = (0, vue_3.ref)('');
const selected: any = (0, vue_3.ref)('');
return (_ctx?: any, _cache?: any) => {
return ((0, vue_2.openBlock)(), (0, vue_2.createElementBlock)("div", _hoisted_1, [
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamAutocomplete), (0, vue_2.mergeProps)({
modelValue: value.value,
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event?: any) => ((value).value = $event))
}, { class: 'field', 'aria-label': '服务补全' }, {
"fetch-suggestions": (0, vue_2.unref)(suggestions_1.suggest),
"value-key": "label",
debounce: 150,
"trigger-on-focus": false,
"highlight-first-item": "",
onSelect: _cache[1] || (_cache[1] = (item?: any) => (selected.value = 'label' in item ? item.label : String(item.value)))
}), {
default: (0, vue_2.withCtx)(({ item }: any) => [
(0, vue_2.createTextVNode)((0, vue_2.toDisplayString)(item.label) + " · " + (0, vue_2.toDisplayString)('code' in item ? item.code : item.value), 1 /* TEXT */)
]),
header: (0, vue_2.withCtx)(() => [...(_cache[2] || (_cache[2] = [
(0, vue_2.createTextVNode)(" 本地服务建议 ", -1 /* CACHED */)
]))]),
footer: (0, vue_2.withCtx)(() => [...(_cache[3] || (_cache[3] = [
(0, vue_2.createTextVNode)(" 输入名称检索 ", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}, 16 /* FULL_PROPS */, ["modelValue", "fetch-suggestions"]),
(0, vue_2.createElementVNode)("output", null, "选择:" + (0, vue_2.toDisplayString)(selected.value), 1 /* TEXT */)
]));
};
}
});
exports.default.__scopeId = "data-v-af4c2619";
},
"suggestions.ts": (module: any, exports: any, require: any) => {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.suggest = suggest;
const services: any = [
{ label: '设计服务', code: 'DES' },
{ label: '开发服务', code: 'DEV' }
];
async function suggest(query?: any) {
return services.filter((item?: any) => item.label.includes(query));
}
},
};
const __dependencies: any = {"Demo.vue":{"./suggestions":"suggestions.ts"},"suggestions.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>
.example[data-v-af4c2619] {
display: grid;
gap: var(--asam-space-md, 16px);
min-width: 0;
}
.row[data-v-af4c2619] {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--asam-space-sm, 8px);
}
.field[data-v-af4c2619] {
width: 100%;
max-width: 360px;
}
output[data-v-af4c2619] {
overflow-wrap: anywhere;
color: var(--asam-color-text-secondary);
}
</style>
<template><StandaloneDemo /></template>
<script setup>
import * as __external0 from "vue";
import * as __external1 from "@asam-ui/ui";
const __external = {"vue": { ...__external0, __esModule: true },
"@asam-ui/ui": { ...__external1, __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: "example" };
const vue_2 = require("vue");
const ui_1 = require("@asam-ui/ui");
const suggestions_1 = require("./suggestions");
exports.default = Object.assign({ name: 'AsamAutocompleteSuggestionsExample' }, {
__name: 'Demo',
setup(__props) {
const value = (0, vue_2.ref)('');
const selected = (0, vue_2.ref)('');
return (_ctx, _cache) => {
return ((0, vue_1.openBlock)(), (0, vue_1.createElementBlock)("div", _hoisted_1, [
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamAutocomplete), (0, vue_1.mergeProps)({
modelValue: value.value,
"onUpdate:modelValue": _cache[0] || (_cache[0] = $event => ((value).value = $event))
}, { class: 'field', 'aria-label': '服务补全' }, {
"fetch-suggestions": (0, vue_1.unref)(suggestions_1.suggest),
"value-key": "label",
debounce: 150,
"trigger-on-focus": false,
"highlight-first-item": "",
onSelect: _cache[1] || (_cache[1] = (item) => (selected.value = 'label' in item ? item.label : String(item.value)))
}), {
default: (0, vue_1.withCtx)(({ item }) => [
(0, vue_1.createTextVNode)((0, vue_1.toDisplayString)(item.label) + " · " + (0, vue_1.toDisplayString)('code' in item ? item.code : item.value), 1 /* TEXT */)
]),
header: (0, vue_1.withCtx)(() => [...(_cache[2] || (_cache[2] = [
(0, vue_1.createTextVNode)(" 本地服务建议 ", -1 /* CACHED */)
]))]),
footer: (0, vue_1.withCtx)(() => [...(_cache[3] || (_cache[3] = [
(0, vue_1.createTextVNode)(" 输入名称检索 ", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}, 16 /* FULL_PROPS */, ["modelValue", "fetch-suggestions"]),
(0, vue_1.createElementVNode)("output", null, "选择:" + (0, vue_1.toDisplayString)(selected.value), 1 /* TEXT */)
]));
};
}
});
exports.default.__scopeId = "data-v-c3eff85c";
},
"suggestions.js": (module, exports, require) => {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.suggest = suggest;
const services = [
{ label: '设计服务', code: 'DES' },
{ label: '开发服务', code: 'DEV' }
];
async function suggest(query) {
return services.filter((item) => item.label.includes(query));
}
},
};
const __dependencies = {"Demo.vue":{"./suggestions":"suggestions.js"},"suggestions.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>
.example[data-v-c3eff85c] {
display: grid;
gap: var(--asam-space-md, 16px);
min-width: 0;
}
.row[data-v-c3eff85c] {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--asam-space-sm, 8px);
}
.field[data-v-c3eff85c] {
width: 100%;
max-width: 360px;
}
output[data-v-c3eff85c] {
overflow-wrap: anywhere;
color: var(--asam-color-text-secondary);
}
</style>
装饰与建议实例 ​
公开状态包含 activated、loading、suggestions、highlightedIndex;getData、handleSelect、handleKeyEnter 是异步实例方法。
实例按钮会先建立输入焦点并等待建议渲染;高亮首项获取“上”的建议后高亮上海,按 Enter 可选中。关闭建议保留已输入的值。示例同时组合 prefix、suffix、prepend、append,并使用 Close 图标提供可操作的清空入口;清空后模型同步为空,可再次获取和选择建议。
装饰与建议实例
<!-- 此演示还使用 @asam-ui/icons-vue,请按官网对应指南配置这些公开依赖。 -->
<template>
<div class="example">
<div class="row">
<AsamButton type="default" @click="focusInput"> 聚焦补全 </AsamButton>
<AsamButton type="default" @click="getCitySuggestions"> 获取建议 </AsamButton>
<AsamButton type="default" @click="highlightFirst"> 高亮首项 </AsamButton>
<AsamButton type="default" @click="input?.close()"> 关闭建议 </AsamButton>
</div>
<AsamAutocomplete
ref="input"
v-model="value"
v-bind="{ class: 'field', 'aria-label': '实例补全' }"
:options="options"
:debounce="0"
clearable
:clear-icon="Close"
>
<template #prefix>
<Search style="width: 16px" />
</template>
<template #suffix> 补全 </template>
<template #prepend> 城市搜索 </template>
<template #append> 城市 </template>
</AsamAutocomplete>
<output>{{ JSON.stringify({ value }) }}</output>
</div>
</template>
<script lang="ts" setup>
defineOptions({ name: 'AsamAutocompleteInstanceExample' });
import { nextTick, ref } from 'vue';
import { AsamAutocomplete, AsamButton } from '@asam-ui/ui';
import type { AsamAutocompleteExpose, AsamOption } from '@asam-ui/ui';
import { Search, Close } from '@asam-ui/icons-vue';
const input = ref<AsamAutocompleteExpose>();
const value = ref('');
const options: AsamOption<string>[] = [
{ value: 'shanghai', label: '上海', raw: { code: 'SH' } },
{ value: 'beijing', label: '北京', raw: { code: 'BJ' } }
];
async function prepareSuggestions(query: string) {
// The button takes focus first. Let the previous native blur close finish
// before establishing a new focused, rendered suggestions panel.
await new Promise<void>((resolve) => setTimeout(resolve, 0));
const control = input.value;
if (!control) return;
control.focus();
await nextTick();
await control.getData(query);
await nextTick();
}
async function focusInput() {
await prepareSuggestions(value.value);
}
async function getCitySuggestions() {
await prepareSuggestions('上');
}
async function highlightFirst() {
await prepareSuggestions('上');
input.value?.highlight(0);
}
</script>
<style scoped>
.example {
--asam-layout-control-width: 100%;
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);
}
.field {
width: 100%;
max-width: 360px;
}
output {
overflow-wrap: anywhere;
color: var(--asam-color-text-secondary);
}
</style>
<!-- 此演示还使用 @asam-ui/icons-vue,请按官网对应指南配置这些公开依赖。 -->
<template>
<div class="example">
<div class="row">
<AsamButton type="default" @click="focusInput"> 聚焦补全 </AsamButton>
<AsamButton type="default" @click="getCitySuggestions"> 获取建议 </AsamButton>
<AsamButton type="default" @click="highlightFirst"> 高亮首项 </AsamButton>
<AsamButton type="default" @click="input?.close()"> 关闭建议 </AsamButton>
</div>
<AsamAutocomplete
ref="input"
v-model="value"
v-bind="{ class: 'field', 'aria-label': '实例补全' }"
:options="options"
:debounce="0"
clearable
:clear-icon="Close"
>
<template #prefix>
<Search style="width: 16px" />
</template>
<template #suffix> 补全 </template>
<template #prepend> 城市搜索 </template>
<template #append> 城市 </template>
</AsamAutocomplete>
<output>{{ JSON.stringify({ value }) }}</output>
</div>
</template>
<script setup>
defineOptions({ name: 'AsamAutocompleteInstanceExample' });
import { nextTick, ref } from 'vue';
import { AsamAutocomplete, AsamButton } from '@asam-ui/ui';
import { Search, Close } from '@asam-ui/icons-vue';
const input = ref();
const value = ref('');
const options = [
{ value: 'shanghai', label: '上海', raw: { code: 'SH' } },
{ value: 'beijing', label: '北京', raw: { code: 'BJ' } }
];
async function prepareSuggestions(query) {
// The button takes focus first. Let the previous native blur close finish
// before establishing a new focused, rendered suggestions panel.
await new Promise((resolve) => setTimeout(resolve, 0));
const control = input.value;
if (!control) return;
control.focus();
await nextTick();
await control.getData(query);
await nextTick();
}
async function focusInput() {
await prepareSuggestions(value.value);
}
async function getCitySuggestions() {
await prepareSuggestions('上');
}
async function highlightFirst() {
await prepareSuggestions('上');
input.value?.highlight(0);
}
</script>
<style scoped>
.example {
--asam-layout-control-width: 100%;
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);
}
.field {
width: 100%;
max-width: 360px;
}
output {
overflow-wrap: anywhere;
color: var(--asam-color-text-secondary);
}
</style>
四档密度与继承 ​
large / big / default / small 分别为四档密度。显式 size 覆盖继承;省略 size 时按组件、组、表单、ConfigProvider 到 default 解析。通过切换 provider 验证继承响应。
四档密度与继承
<template>
<div class="example">
<div class="row">
<AsamAutocomplete
size="large"
v-bind="{ class: 'field', 'aria-label': 'large尺寸' }"
model-value="ASAM"
:fetch-suggestions="[]"
/>
<AsamAutocomplete
size="big"
v-bind="{ class: 'field', 'aria-label': 'big尺寸' }"
model-value="ASAM"
:fetch-suggestions="[]"
/>
<AsamAutocomplete
size="default"
v-bind="{ class: 'field', 'aria-label': 'default尺寸' }"
model-value="ASAM"
:fetch-suggestions="[]"
/>
<AsamAutocomplete
size="small"
v-bind="{ class: 'field', 'aria-label': 'small尺寸' }"
model-value="ASAM"
:fetch-suggestions="[]"
/>
</div>
<AsamConfigProvider :size="density">
<div class="example">
<AsamAutocomplete
v-bind="{ class: 'field', 'aria-label': '继承尺寸' }"
model-value="ASAM"
:fetch-suggestions="[]"
/>
<div class="row">
<AsamButton type="default" @click="density = 'small'"> 继承 small </AsamButton>
<AsamButton type="default" @click="density = 'big'"> 继承 big </AsamButton>
</div>
</div>
</AsamConfigProvider>
<output>配置提供器:{{ density }}</output>
</div>
</template>
<script lang="ts" setup>
defineOptions({ name: 'AsamAutocompleteSizesExample' });
import { ref } from 'vue';
import { AsamAutocomplete, 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);
}
.field {
width: 100%;
max-width: 360px;
}
output {
overflow-wrap: anywhere;
color: var(--asam-color-text-secondary);
}
</style>
<template>
<div class="example">
<div class="row">
<AsamAutocomplete
size="large"
v-bind="{ class: 'field', 'aria-label': 'large尺寸' }"
model-value="ASAM"
:fetch-suggestions="[]"
/>
<AsamAutocomplete
size="big"
v-bind="{ class: 'field', 'aria-label': 'big尺寸' }"
model-value="ASAM"
:fetch-suggestions="[]"
/>
<AsamAutocomplete
size="default"
v-bind="{ class: 'field', 'aria-label': 'default尺寸' }"
model-value="ASAM"
:fetch-suggestions="[]"
/>
<AsamAutocomplete
size="small"
v-bind="{ class: 'field', 'aria-label': 'small尺寸' }"
model-value="ASAM"
:fetch-suggestions="[]"
/>
</div>
<AsamConfigProvider :size="density">
<div class="example">
<AsamAutocomplete
v-bind="{ class: 'field', 'aria-label': '继承尺寸' }"
model-value="ASAM"
:fetch-suggestions="[]"
/>
<div class="row">
<AsamButton type="default" @click="density = 'small'"> 继承 small </AsamButton>
<AsamButton type="default" @click="density = 'big'"> 继承 big </AsamButton>
</div>
</div>
</AsamConfigProvider>
<output>配置提供器:{{ density }}</output>
</div>
</template>
<script setup>
defineOptions({ name: 'AsamAutocompleteSizesExample' });
import { ref } from 'vue';
import { AsamAutocomplete, 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);
}
.field {
width: 100%;
max-width: 360px;
}
output {
overflow-wrap: anywhere;
color: var(--asam-color-text-secondary);
}
</style>
ASAM 扩展与迁移 ​
ASAM 扩展是 options、maxSuggestions 与原对象回传。 完整说明。
浮层配置 ​
showArrow 与 popperOptions 作用于实际建议浮层;teleported 控制是否传送,appendTo 可指定容器,fitInputWidth 匹配输入宽度。popperClass/popperStyle 配置浮层样式;传送到 body 的浮层不会自动继承局部主题变量。
浮层定位、箭头与容器
<template>
<div class="example">
<AsamCheckboxItem v-model="arrow">显示箭头</AsamCheckboxItem
><AsamCheckboxItem v-model="teleported">传送到 body</AsamCheckboxItem
><AsamAutocomplete
v-model="query"
:options="options"
:show-arrow="arrow"
:popper-options="popperOptions"
:teleported="teleported"
:fit-input-width="true"
popper-class="example-suggestion"
aria-label="定位建议"
>
<template #header>建议列表</template><template #footer>方向键选择,Esc关闭</template>
</AsamAutocomplete>
</div>
</template>
<script lang="ts" setup>
defineOptions({ name: 'AsamAutocompletePopperExample' });
import { ref } from 'vue';
import { AsamCheckboxItem, AsamAutocomplete } from '@asam-ui/ui';
const query = ref('');
const arrow = ref(true);
const teleported = ref(true);
const options = [
{ value: 'a', label: 'Alpha', raw: {} },
{ value: 'b', label: 'Beta', raw: {} }
];
const popperOptions = {
strategy: 'fixed' as const,
modifiers: [{ name: 'offset', options: { offset: [0, 20] } }]
};
</script>
<style scoped>
.example {
display: grid;
gap: var(--asam-space-md);
min-width: 0;
}
.row {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--asam-space-sm);
}
output {
color: var(--asam-color-text-secondary);
overflow-wrap: anywhere;
}
</style>
<template>
<div class="example">
<AsamCheckboxItem v-model="arrow">显示箭头</AsamCheckboxItem
><AsamCheckboxItem v-model="teleported">传送到 body</AsamCheckboxItem
><AsamAutocomplete
v-model="query"
:options="options"
:show-arrow="arrow"
:popper-options="popperOptions"
:teleported="teleported"
:fit-input-width="true"
popper-class="example-suggestion"
aria-label="定位建议"
>
<template #header>建议列表</template><template #footer>方向键选择,Esc关闭</template>
</AsamAutocomplete>
</div>
</template>
<script setup>
defineOptions({ name: 'AsamAutocompletePopperExample' });
import { ref } from 'vue';
import { AsamCheckboxItem, AsamAutocomplete } from '@asam-ui/ui';
const query = ref('');
const arrow = ref(true);
const teleported = ref(true);
const options = [
{ value: 'a', label: 'Alpha', raw: {} },
{ value: 'b', label: 'Beta', raw: {} }
];
const popperOptions = {
strategy: 'fixed',
modifiers: [{ name: 'offset', options: { offset: [0, 20] } }]
};
</script>
<style scoped>
.example {
display: grid;
gap: var(--asam-space-md);
min-width: 0;
}
.row {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--asam-space-sm);
}
output {
color: var(--asam-color-text-secondary);
overflow-wrap: anywhere;
}
</style>
异步建议与键盘提交 ​
fetchSuggestions 支持数组、回调、同步数组或 Promise;设置它时优先于 ASAM options/remoteSuggestions,原生建议不会被 maxSuggestions 截断。 完整说明。
debounce 控制查询防抖,triggerOnFocus 控制聚焦查询,highlightFirstItem 高亮首项,loopNavigation 决定方向键是否环绕。 完整说明。
select 的类型为 T | AsamOption<V, I> | { value: string | number }。 完整说明。
异步建议、加载与未匹配提交
<template>
<div class="example">
<AsamAutocomplete
v-model="query"
:fetch-suggestions="fetchSuggestions"
:debounce="100"
:trigger-on-focus="false"
select-when-unmatched
highlight-first-item
:loop-navigation="false"
aria-label="异步建议"
@select="handleSelect"
>
<template #default="{ item }">
{{ item.value }} · {{ 'id' in item ? item.id : '' }}
</template>
<template #loading>查询中,请稍候</template>
</AsamAutocomplete>
<output>选择:{{ selected }}</output>
<p class="example-paragraph">
输入后等待本地异步建议,选择建议查看完整对象。输入“自由输入”后等待空建议再按
Enter,查看只有 value 的载荷;消费方先收窄再读取完整候选字段。
</p>
</div>
</template>
<script lang="ts" setup>
defineOptions({ name: 'AsamAutocompleteAsyncExample' });
import { ref } from 'vue';
import { AsamAutocomplete } from '@asam-ui/ui';
import type { AsamAutocompleteEmits, AsamValue, AsamRecord } from '@asam-ui/ui';
interface Suggestion {
value: string;
id: number;
}
const query = ref('');
const selected = ref('');
async function fetchSuggestions(query: string): Promise<Suggestion[]> {
await new Promise((resolve) => setTimeout(resolve, 400));
return query === '自由输入' ? [] : [{ value: query + ' suggestion', id: 42 }];
}
function handleSelect(item: AsamAutocompleteEmits<AsamValue, AsamRecord, Suggestion>['select'][0]) {
if ('id' in item) selected.value = `匹配建议 #${item.id}:${JSON.stringify(item)}`;
else if ('label' in item) selected.value = `匹配选项 ${item.label}:${JSON.stringify(item)}`;
else selected.value = `未匹配:${JSON.stringify(item)}`;
}
</script>
<style scoped>
.example {
display: grid;
gap: var(--asam-space-md);
min-width: 0;
}
.row {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--asam-space-sm);
}
output {
color: var(--asam-color-text-secondary);
overflow-wrap: anywhere;
}
</style>
<style scoped>
p:where(.example-paragraph) {
margin-block: 16px;
line-height: 1.8;
overflow-wrap: anywhere;
}
</style>
<template>
<div class="example">
<AsamAutocomplete
v-model="query"
:fetch-suggestions="fetchSuggestions"
:debounce="100"
:trigger-on-focus="false"
select-when-unmatched
highlight-first-item
:loop-navigation="false"
aria-label="异步建议"
@select="handleSelect"
>
<template #default="{ item }">
{{ item.value }} · {{ 'id' in item ? item.id : '' }}
</template>
<template #loading>查询中,请稍候</template>
</AsamAutocomplete>
<output>选择:{{ selected }}</output>
<p class="example-paragraph">
输入后等待本地异步建议,选择建议查看完整对象。输入“自由输入”后等待空建议再按
Enter,查看只有 value 的载荷;消费方先收窄再读取完整候选字段。
</p>
</div>
</template>
<script setup>
defineOptions({ name: 'AsamAutocompleteAsyncExample' });
import { ref } from 'vue';
import { AsamAutocomplete } from '@asam-ui/ui';
const query = ref('');
const selected = ref('');
async function fetchSuggestions(query) {
await new Promise((resolve) => setTimeout(resolve, 400));
return query === '自由输入' ? [] : [{ value: query + ' suggestion', id: 42 }];
}
function handleSelect(item) {
if ('id' in item) selected.value = `匹配建议 #${item.id}:${JSON.stringify(item)}`;
else if ('label' in item) selected.value = `匹配选项 ${item.label}:${JSON.stringify(item)}`;
else selected.value = `未匹配:${JSON.stringify(item)}`;
}
</script>
<style scoped>
.example {
display: grid;
gap: var(--asam-space-md);
min-width: 0;
}
.row {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--asam-space-sm);
}
output {
color: var(--asam-color-text-secondary);
overflow-wrap: anywhere;
}
</style>
<style scoped>
p:where(.example-paragraph) {
margin-block: 16px;
line-height: 1.8;
overflow-wrap: anywhere;
}
</style>
数组、回调和 Promise 协议
<template>
<div class="example">
<AsamAutocomplete
v-model="arrayValue"
:fetch-suggestions="items"
aria-label="数组建议"
/><AsamAutocomplete
v-model="callbackValue"
:fetch-suggestions="callback"
select-when-unmatched
aria-label="回调建议"
@select="selected = JSON.stringify($event)"
/><AsamAutocomplete
v-model="promiseValue"
:fetch-suggestions="promise"
aria-label="Promise建议"
/><output>{{ selected }}</output>
</div>
</template>
<script lang="ts" setup>
defineOptions({ name: 'AsamAutocompleteNativeProtocolsExample' });
import { ref } from 'vue';
import { AsamAutocomplete } from '@asam-ui/ui';
const arrayValue = ref('');
const callbackValue = ref('');
const promiseValue = ref('');
const selected = ref('');
const items = [
{ value: 'Alpha', code: 'a' },
{ value: 'Beta', code: 'b' }
];
const filter = (query: string) =>
items.filter((item) => item.value.toLowerCase().includes(query.toLowerCase()));
function callback(query: string, done: (items: { value: string; code: string }[]) => void) {
done(filter(query));
}
async function promise(query: string) {
return filter(query);
}
</script>
<style scoped>
.example {
display: grid;
gap: var(--asam-space-md);
min-width: 0;
}
.row {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--asam-space-sm);
}
output {
color: var(--asam-color-text-secondary);
overflow-wrap: anywhere;
}
</style>
<template>
<div class="example">
<AsamAutocomplete
v-model="arrayValue"
:fetch-suggestions="items"
aria-label="数组建议"
/><AsamAutocomplete
v-model="callbackValue"
:fetch-suggestions="callback"
select-when-unmatched
aria-label="回调建议"
@select="selected = JSON.stringify($event)"
/><AsamAutocomplete
v-model="promiseValue"
:fetch-suggestions="promise"
aria-label="Promise建议"
/><output>{{ selected }}</output>
</div>
</template>
<script setup>
defineOptions({ name: 'AsamAutocompleteNativeProtocolsExample' });
import { ref } from 'vue';
import { AsamAutocomplete } from '@asam-ui/ui';
const arrayValue = ref('');
const callbackValue = ref('');
const promiseValue = ref('');
const selected = ref('');
const items = [
{ value: 'Alpha', code: 'a' },
{ value: 'Beta', code: 'b' }
];
const filter = (query) =>
items.filter((item) => item.value.toLowerCase().includes(query.toLowerCase()));
function callback(query, done) {
done(filter(query));
}
async function promise(query) {
return filter(query);
}
</script>
<style scoped>
.example {
display: grid;
gap: var(--asam-space-md);
min-width: 0;
}
.row {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--asam-space-sm);
}
output {
color: var(--asam-color-text-secondary);
overflow-wrap: anywhere;
}
</style>
API 阅读方式 ​
下方 API 来自当前公开类型与运行默认值。默认值标为“未知 / 未声明”时,不代表 false、空值或未支持。省略 size 保留祖先上下文继承。省略 disabled 保留表单禁用继承;validateEvent 控制校验事件,不用 disabled 代替。
省略 showArrow 时沿用原生 true 默认;显式 false 隐藏建议浮层箭头。
完整继承输入组合 ​
min/max/step、formatter/parser、modelModifiers 与 textarea 参数原样交给 底层输入。 完整说明。
ASAM options/remoteSuggestions 分支继续按 label 过滤、忽略 disabled 项并保留原选项对象与 maxSuggestions 上限。 完整说明。
完整继承输入组合
<template>
<div class="example">
<AsamAutocomplete
v-model="numeric"
:fetch-suggestions="options"
type="number"
:min="1"
:max="9"
:step="0.5"
aria-label="原生约束"
/>
<AsamAutocomplete
v-model="amount"
:fetch-suggestions="options"
:formatter="formatter"
:parser="parser"
aria-label="继承格式化"
/>
<AsamAutocomplete
v-model.trim.number.lazy="modified"
:fetch-suggestions="options"
aria-label="提及或建议修饰符"
@update:model-value="record"
/>
<AsamButton type="default" native-type="button" @click="modified = 42"
>外部设置 42</AsamButton
>
<AsamAutocomplete
v-model="text"
:fetch-suggestions="options"
type="textarea"
:autosize="{ minRows: 2, maxRows: 4 }"
:maxlength="3"
show-word-limit
word-limit-position="outside"
:count-graphemes="countGraphemes"
aria-label="多行建议与字素"
/>
<AsamButton type="default" native-type="button">移出焦点提交</AsamButton>
<output>{{ JSON.stringify({ numeric, amount, modified, text, updates }) }}</output>
<p class="example-paragraph">
原生数字约束作用于实际 input;formatter/parser 改变显示并解析模型;number
修饰符可更新为数字,再传入仍正确显示;textarea 与字素计数适用于本入口的提及或建议。
</p>
</div>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import { AsamButton, AsamAutocomplete } from '@asam-ui/ui';
import type { AsamAutocompleteEmits } from '@asam-ui/ui';
defineOptions({ name: 'AsamAutocompleteNativeInputExample' });
const options = [{ value: 'Alice', label: 'Alice' }];
const numeric = ref<string | number>('1');
const amount = ref<string | number>('1234');
const modified = ref<string | number>('');
const text = ref('👩👩👧👦');
const updates = ref<(string | number)[]>([]);
function record(...[value]: AsamAutocompleteEmits['update:modelValue']) {
updates.value.push(value);
}
const formatter = (value: string) =>
value === '' ? '' : '$' + value.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
const parser = (value: string) => value.replace(/[$,]/g, '');
const countGraphemes = (value: string) => Array.from(new Intl.Segmenter().segment(value)).length;
</script>
<style scoped>
.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>
<div class="example">
<AsamAutocomplete
v-model="numeric"
:fetch-suggestions="options"
type="number"
:min="1"
:max="9"
:step="0.5"
aria-label="原生约束"
/>
<AsamAutocomplete
v-model="amount"
:fetch-suggestions="options"
:formatter="formatter"
:parser="parser"
aria-label="继承格式化"
/>
<AsamAutocomplete
v-model.trim.number.lazy="modified"
:fetch-suggestions="options"
aria-label="提及或建议修饰符"
@update:model-value="record"
/>
<AsamButton type="default" native-type="button" @click="modified = 42"
>外部设置 42</AsamButton
>
<AsamAutocomplete
v-model="text"
:fetch-suggestions="options"
type="textarea"
:autosize="{ minRows: 2, maxRows: 4 }"
:maxlength="3"
show-word-limit
word-limit-position="outside"
:count-graphemes="countGraphemes"
aria-label="多行建议与字素"
/>
<AsamButton type="default" native-type="button">移出焦点提交</AsamButton>
<output>{{ JSON.stringify({ numeric, amount, modified, text, updates }) }}</output>
<p class="example-paragraph">
原生数字约束作用于实际 input;formatter/parser 改变显示并解析模型;number
修饰符可更新为数字,再传入仍正确显示;textarea 与字素计数适用于本入口的提及或建议。
</p>
</div>
</template>
<script setup>
import { ref } from 'vue';
import { AsamButton, AsamAutocomplete } from '@asam-ui/ui';
defineOptions({ name: 'AsamAutocompleteNativeInputExample' });
const options = [{ value: 'Alice', label: 'Alice' }];
const numeric = ref('1');
const amount = ref('1234');
const modified = ref('');
const text = ref('👩👩👧👦');
const updates = ref([]);
function record(...[value]) {
updates.value.push(value);
}
const formatter = (value) =>
value === '' ? '' : '$' + value.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
const parser = (value) => value.replace(/[$,]/g, '');
const countGraphemes = (value) => Array.from(new Intl.Segmenter().segment(value)).length;
</script>
<style scoped>
.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>
五入口表单继承与校验 ​
本完整 TS/JS 组合实际实例化单行、密码、多行、建议和标签五个入口。省略各入口 disabled 以继承表单状态;validateEvent 控制各自 change/blur 自动校验。切换禁用不会清空模型,关闭自动校验不影响编辑。五页注册同一组合源码的自包含副本,复制当前示例即可运行,无需从其他组件页补齐文件。
五入口表单继承与校验
<template>
<!-- prettier-ignore -->
<div class="example">
<AsamCheckboxItem
v-model="disabled"
aria-label="禁用五入口表单">禁用整个表单</AsamCheckboxItem>
<AsamCheckboxItem v-model="validateEvent" aria-label="五入口自动校验">自动
change/blur 校验</AsamCheckboxItem>
<AsamBaseForm
ref="form"
:model="model"
:rules="rules"
:disabled="disabled"
@validate="record"
>
<AsamFormItem
label="单行"
prop="input"
>
<AsamInput
v-model="model.input"
:validate-event="validateEvent"
aria-label="表单单行"
/>
</AsamFormItem>
<AsamFormItem
label="密码"
prop="password"
>
<AsamPassword
v-model="model.password"
:validate-event="validateEvent"
aria-label="表单密码"
/>
</AsamFormItem>
<AsamFormItem
label="多行"
prop="textarea"
>
<AsamTextarea
v-model="model.textarea"
:validate-event="validateEvent"
aria-label="表单多行"
/>
</AsamFormItem>
<AsamFormItem
label="建议"
prop="autocomplete"
>
<AsamAutocomplete
v-model="model.autocomplete"
:fetch-suggestions="suggestions"
:validate-event="validateEvent"
aria-label="表单建议"
/>
</AsamFormItem>
<AsamFormItem
label="标签"
prop="tags"
>
<AsamInputTag
v-model="model.tags"
:validate-event="validateEvent"
aria-label="表单标签"
/>
</AsamFormItem>
</AsamBaseForm>
<AsamButton type="default" native-type="button" @click="reset">重置模型和校验记录</AsamButton>
<AsamButton type="default" native-type="button">提交编辑</AsamButton>
<output>{{ JSON.stringify({ model, disabled, validateEvent, validations }) }}</output>
</div>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import {
AsamCheckboxItem,
AsamButton,
AsamBaseForm,
AsamFormItem,
AsamInput,
AsamPassword,
AsamTextarea,
AsamAutocomplete,
AsamInputTag
} from '@asam-ui/ui';
import type { AsamBaseFormExpose } from '@asam-ui/ui';
defineOptions({ name: 'AsamFiveInputsFormExample' });
const model = ref({
input: '',
password: '',
textarea: '',
autocomplete: '',
tags: [] as string[]
});
const disabled = ref(false);
const validateEvent = ref(true);
const form = ref<AsamBaseFormExpose>();
const rules = Object.fromEntries(
['input', 'password', 'textarea', 'autocomplete', 'tags'].map((key) => [
key,
[{ required: true, message: '请完善此项', trigger: ['change', 'blur'] }]
])
);
const suggestions = [{ value: 'Alpha' }];
const validations = ref<{ prop: string; valid: boolean }[]>([]);
function record(prop: string | string[], valid: boolean) {
validations.value.push({ prop: String(prop), valid });
}
function reset() {
model.value = { input: '', password: '', textarea: '', autocomplete: '', tags: [] };
validations.value = [];
form.value?.clearValidate();
}
</script>
<style scoped>
.example {
display: grid;
gap: var(--asam-space-md);
}
</style>
<template>
<!-- prettier-ignore -->
<div class="example">
<AsamCheckboxItem
v-model="disabled"
aria-label="禁用五入口表单">禁用整个表单</AsamCheckboxItem>
<AsamCheckboxItem v-model="validateEvent" aria-label="五入口自动校验">自动
change/blur 校验</AsamCheckboxItem>
<AsamBaseForm
ref="form"
:model="model"
:rules="rules"
:disabled="disabled"
@validate="record"
>
<AsamFormItem
label="单行"
prop="input"
>
<AsamInput
v-model="model.input"
:validate-event="validateEvent"
aria-label="表单单行"
/>
</AsamFormItem>
<AsamFormItem
label="密码"
prop="password"
>
<AsamPassword
v-model="model.password"
:validate-event="validateEvent"
aria-label="表单密码"
/>
</AsamFormItem>
<AsamFormItem
label="多行"
prop="textarea"
>
<AsamTextarea
v-model="model.textarea"
:validate-event="validateEvent"
aria-label="表单多行"
/>
</AsamFormItem>
<AsamFormItem
label="建议"
prop="autocomplete"
>
<AsamAutocomplete
v-model="model.autocomplete"
:fetch-suggestions="suggestions"
:validate-event="validateEvent"
aria-label="表单建议"
/>
</AsamFormItem>
<AsamFormItem
label="标签"
prop="tags"
>
<AsamInputTag
v-model="model.tags"
:validate-event="validateEvent"
aria-label="表单标签"
/>
</AsamFormItem>
</AsamBaseForm>
<AsamButton type="default" native-type="button" @click="reset">重置模型和校验记录</AsamButton>
<AsamButton type="default" native-type="button">提交编辑</AsamButton>
<output>{{ JSON.stringify({ model, disabled, validateEvent, validations }) }}</output>
</div>
</template>
<script setup>
import { ref } from 'vue';
import {
AsamCheckboxItem,
AsamButton,
AsamBaseForm,
AsamFormItem,
AsamInput,
AsamPassword,
AsamTextarea,
AsamAutocomplete,
AsamInputTag
} from '@asam-ui/ui';
defineOptions({ name: 'AsamFiveInputsFormExample' });
const model = ref({ input: '', password: '', textarea: '', autocomplete: '', tags: [] });
const disabled = ref(false);
const validateEvent = ref(true);
const form = ref();
const rules = Object.fromEntries(
['input', 'password', 'textarea', 'autocomplete', 'tags'].map((key) => [
key,
[{ required: true, message: '请完善此项', trigger: ['change', 'blur'] }]
])
);
const suggestions = [{ value: 'Alpha' }];
const validations = ref([]);
function record(prop, valid) {
validations.value.push({ prop: String(prop), valid });
}
function reset() {
model.value = { input: '', password: '', textarea: '', autocomplete: '', tags: [] };
validations.value = [];
form.value?.clearValidate();
}
</script>
<style scoped>
.example {
display: grid;
gap: var(--asam-space-md);
}
</style>
异步建议与动态只读禁用 ​
readonly、disabled 和继承表单状态原样委托原生。它们控制原生 UI 的可编辑性;公开 handleSelect、键盘选择及异步建议期间的具体行为以 底层输入 2.14.7 为准,ASAM 不额外过滤原生发出的模型和 select 事件。父级仍可更新模型。
异步建议与动态只读禁用
<template>
<!-- prettier-ignore -->
<div class="example">
<AsamCheckboxItem v-model="readonly">只读</AsamCheckboxItem>
<AsamCheckboxItem v-model="disabled">禁用表单</AsamCheckboxItem>
<AsamBaseForm
:model="{ value }"
:disabled="disabled"
>
<AsamAutocomplete
v-model="value"
:readonly="readonly"
:fetch-suggestions="suggestions"
highlight-first-item
aria-label="动态异步建议"
@update:model-value="events.push('update')"
@select="events.push('select')"
/>
</AsamBaseForm>
<output>{{ JSON.stringify({ value, readonly, disabled, events }) }}</output>
</div>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import { AsamCheckboxItem, AsamBaseForm, AsamAutocomplete } from '@asam-ui/ui';
defineOptions({ name: 'AsamAutocompleteStateExample' });
const value = ref('');
const readonly = ref(true);
const disabled = ref(false);
const events = ref<string[]>([]);
async function suggestions() {
await new Promise((resolve) => setTimeout(resolve, 150));
return [{ value: 'Alpha' }];
}
</script>
<style scoped>
.example {
display: grid;
gap: var(--asam-space-md);
}
</style>
<template>
<!-- prettier-ignore -->
<div class="example">
<AsamCheckboxItem v-model="readonly">只读</AsamCheckboxItem>
<AsamCheckboxItem v-model="disabled">禁用表单</AsamCheckboxItem>
<AsamBaseForm
:model="{ value }"
:disabled="disabled"
>
<AsamAutocomplete
v-model="value"
:readonly="readonly"
:fetch-suggestions="suggestions"
highlight-first-item
aria-label="动态异步建议"
@update:model-value="events.push('update')"
@select="events.push('select')"
/>
</AsamBaseForm>
<output>{{ JSON.stringify({ value, readonly, disabled, events }) }}</output>
</div>
</template>
<script setup>
import { ref } from 'vue';
import { AsamCheckboxItem, AsamBaseForm, AsamAutocomplete } from '@asam-ui/ui';
defineOptions({ name: 'AsamAutocompleteStateExample' });
const value = ref('');
const readonly = ref(true);
const disabled = ref(false);
const events = ref([]);
async function suggestions() {
await new Promise((resolve) => setTimeout(resolve, 150));
return [{ value: 'Alpha' }];
}
</script>
<style scoped>
.example {
display: grid;
gap: var(--asam-space-md);
}
</style>
继承输入事件 ​
compositionstart、compositionupdate、compositionend 的参数均为 CompositionEvent,携带输入合成数据。 完整说明。
继承输入事件与候选键盘操作
<template>
<div class="example">
<AsamAutocomplete
v-model="value"
:options="options"
:debounce="0"
clearable
aria-label="补全继承输入事件"
@keydown="keyed"
@mouseenter="entered"
@mouseleave="left"
@compositionstart="started"
@compositionupdate="updated"
@compositionend="ended"
@select="record('select', $event)"
/>
<AsamButton type="default" native-type="button">移出输入焦点</AsamButton>
<output>{{ JSON.stringify({ value, events }) }}</output>
</div>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import { AsamButton, AsamAutocomplete } from '@asam-ui/ui';
import type { AsamAutocompleteEmits } from '@asam-ui/ui';
defineOptions({ name: 'AsamAutocompleteEventsDemo' });
const value = ref('');
const options = [{ value: 'alpha', label: 'Alpha', raw: { id: 'alpha' } }];
const events = ref<{ name: string; value: unknown }[]>([]);
function record(name: string, value: unknown) {
events.value.push({ name, value });
}
function keyed(...[event]: AsamAutocompleteEmits['keydown']) {
record('keydown', event instanceof KeyboardEvent ? event.key : event.type);
}
function entered(...[event]: AsamAutocompleteEmits['mouseenter']) {
record('mouseenter', event.type);
}
function left(...[event]: AsamAutocompleteEmits['mouseleave']) {
record('mouseleave', event.type);
}
function started(...[event]: AsamAutocompleteEmits['compositionstart']) {
record('compositionstart', event.data);
}
function updated(...[event]: AsamAutocompleteEmits['compositionupdate']) {
record('compositionupdate', event.data);
}
function ended(...[event]: AsamAutocompleteEmits['compositionend']) {
record('compositionend', event.data);
}
</script>
<style scoped>
.example {
display: grid;
gap: var(--asam-space-md);
}
</style>
<template>
<div class="example">
<AsamAutocomplete
v-model="value"
:options="options"
:debounce="0"
clearable
aria-label="补全继承输入事件"
@keydown="keyed"
@mouseenter="entered"
@mouseleave="left"
@compositionstart="started"
@compositionupdate="updated"
@compositionend="ended"
@select="record('select', $event)"
/>
<AsamButton type="default" native-type="button">移出输入焦点</AsamButton>
<output>{{ JSON.stringify({ value, events }) }}</output>
</div>
</template>
<script setup>
import { ref } from 'vue';
import { AsamButton, AsamAutocomplete } from '@asam-ui/ui';
defineOptions({ name: 'AsamAutocompleteEventsDemo' });
const value = ref('');
const options = [{ value: 'alpha', label: 'Alpha', raw: { id: 'alpha' } }];
const events = ref([]);
function record(name, value) {
events.value.push({ name, value });
}
function keyed(...[event]) {
record('keydown', event instanceof KeyboardEvent ? event.key : event.type);
}
function entered(...[event]) {
record('mouseenter', event.type);
}
function left(...[event]) {
record('mouseleave', event.type);
}
function started(...[event]) {
record('compositionstart', event.data);
}
function updated(...[event]) {
record('compositionupdate', event.data);
}
function ended(...[event]) {
record('compositionend', event.data);
}
</script>
<style scoped>
.example {
display: grid;
gap: var(--asam-space-md);
}
</style>
动态原生类型与状态保留 ​
在同一入口切换 text、password 与 number,观察父级模型、焦点和前缀插槽。类型切换、未提交 lazy 值及不支持文本选区的 number 模式都由原生处理;本入口不替换 setSelectionRange 或修复原生光标行为。textarea 使用原生 textarea DOM 形态。
动态原生类型与状态保留
<template><StandaloneDemo /></template>
<script lang="ts" setup>
import * as __external0 from "vue";
import * as __external1 from "@asam-ui/ui";
const __external: any = {"vue": { ...__external0, __esModule: true },
"@asam-ui/ui": { ...__external1, __esModule: true }};
const __modules: any = {
"Demo.vue": (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 });
const vue_1: any = require("vue");
const vue_2: any = require("vue");
const _hoisted_1: any = { class: "example" };
const _hoisted_2: any = { class: "actions" };
const vue_3: any = require("vue");
const ui_1: any = require("@asam-ui/ui");
const SlotCounter_vue_1: any = __importDefault(require("./SlotCounter.vue"));
exports.default = (0, vue_1.defineComponent)({
...{ name: 'AsamAutocompleteDynamicTypeExample' },
__name: 'Demo',
setup(__props?: any) {
const kinds: any = ['text', 'password', 'number'];
const type: any = (0, vue_3.ref)('text');
const value: any = (0, vue_3.ref)('42');
const inputs: any = (0, vue_3.ref)([]);
const suggestions: any = [{ value: '4', label: '四' }];
return (_ctx?: any, _cache?: any) => {
return ((0, vue_2.openBlock)(), (0, vue_2.createElementBlock)("div", _hoisted_1, [
(0, vue_2.createElementVNode)("div", _hoisted_2, [
((0, vue_2.openBlock)(), (0, vue_2.createElementBlock)(vue_2.Fragment, null, (0, vue_2.renderList)(kinds, (kind?: any) => {
return (0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamButton), {
type: "default",
key: kind,
"native-type": "button",
onPointerdown: _cache[0] || (_cache[0] = (0, vue_2.withModifiers)(() => { }, ["prevent"])),
onClick: ($event?: any) => (type.value = kind)
}, {
default: (0, vue_2.withCtx)(() => [
(0, vue_2.createTextVNode)((0, vue_2.toDisplayString)(kind), 1 /* TEXT */)
]),
_: 2 /* DYNAMIC */
}, 1032 /* PROPS, DYNAMIC_SLOTS */, ["onClick"]);
}), 64 /* STABLE_FRAGMENT */)),
_cache[3] || (_cache[3] = (0, vue_2.createElementVNode)("span", null, "先输入 42,再保持焦点切换类型;前缀按钮的计数应保留。", -1 /* CACHED */))
]),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamAutocomplete), {
modelValue: value.value,
"onUpdate:modelValue": _cache[1] || (_cache[1] = ($event?: any) => ((value).value = $event)),
type: type.value,
min: 2,
max: 10,
step: 2,
"fetch-suggestions": suggestions,
"trigger-on-focus": false,
"aria-label": "动态输入类型",
onInput: _cache[2] || (_cache[2] = ($event?: any) => (inputs.value.push($event)))
}, {
prefix: (0, vue_2.withCtx)(() => [
(0, vue_2.createVNode)(SlotCounter_vue_1.default)
]),
_: 1 /* STABLE */
}, 8 /* PROPS */, ["modelValue", "type"]),
(0, vue_2.createElementVNode)("output", null, (0, vue_2.toDisplayString)(JSON.stringify({ type: type.value, value: value.value, inputs: inputs.value })), 1 /* TEXT */),
_cache[4] || (_cache[4] = (0, vue_2.createElementVNode)("p", { class: "example-paragraph" }, " number 的 min/max/step 保留原生约束;切回 text 或 password 后继续编辑。类型切换与光标行为由底层输入处理。number 不支持文本选区,调用文本选区方法可能抛出 InvalidStateError;此入口不补做游标恢复,也不保证未提交编辑值或焦点跨类型保留。 ", -1 /* CACHED */))
]));
};
}
});
exports.default.__scopeId = "data-v-ef659869";
},
"SlotCounter.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 ui_1: any = require("@asam-ui/ui");
const vue_3: any = require("vue");
exports.default = (0, vue_1.defineComponent)({
__name: 'SlotCounter',
setup(__props?: any) {
const count: any = (0, vue_3.ref)(0);
return (_ctx?: any, _cache?: any) => {
return ((0, vue_2.openBlock)(), (0, vue_2.createBlock)((0, vue_2.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: _cache[0] || (_cache[0] = ($event?: any) => (count.value++))
}, {
default: (0, vue_2.withCtx)(() => [
(0, vue_2.createTextVNode)("前缀计数 " + (0, vue_2.toDisplayString)(count.value), 1 /* TEXT */)
]),
_: 1 /* STABLE */
}));
};
}
});
},
};
const __dependencies: any = {"Demo.vue":{"./SlotCounter.vue":"SlotCounter.vue"},"SlotCounter.vue":{}};
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>
.example[data-v-ef659869] {
display: grid;
gap: var(--asam-space-md);
}
.actions[data-v-ef659869] {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--asam-space-sm);
}
output[data-v-ef659869] {
overflow-wrap: anywhere;
}
p[data-v-ef659869]:where(.example-paragraph) {
margin-block: 16px;
line-height: 1.8;
overflow-wrap: anywhere;
}
</style>
<template><StandaloneDemo /></template>
<script setup>
import * as __external0 from "vue";
import * as __external1 from "@asam-ui/ui";
const __external = {"vue": { ...__external0, __esModule: true },
"@asam-ui/ui": { ...__external1, __esModule: true }};
const __modules = {
"Demo.vue": (module, exports, require) => {
"use strict";
var __importDefault = function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const vue_1 = require("vue");
const _hoisted_1 = { class: "example" };
const _hoisted_2 = { class: "actions" };
const vue_2 = require("vue");
const ui_1 = require("@asam-ui/ui");
const SlotCounter_vue_1 = __importDefault(require("./SlotCounter.vue"));
exports.default = Object.assign({ name: 'AsamAutocompleteDynamicTypeExample' }, {
__name: 'Demo',
setup(__props) {
const kinds = ['text', 'password', 'number'];
const type = (0, vue_2.ref)('text');
const value = (0, vue_2.ref)('42');
const inputs = (0, vue_2.ref)([]);
const suggestions = [{ value: '4', label: '四' }];
return (_ctx, _cache) => {
return ((0, vue_1.openBlock)(), (0, vue_1.createElementBlock)("div", _hoisted_1, [
(0, vue_1.createElementVNode)("div", _hoisted_2, [
((0, vue_1.openBlock)(), (0, vue_1.createElementBlock)(vue_1.Fragment, null, (0, vue_1.renderList)(kinds, (kind) => {
return (0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamButton), {
type: "default",
key: kind,
"native-type": "button",
onPointerdown: _cache[0] || (_cache[0] = (0, vue_1.withModifiers)(() => { }, ["prevent"])),
onClick: $event => (type.value = kind)
}, {
default: (0, vue_1.withCtx)(() => [
(0, vue_1.createTextVNode)((0, vue_1.toDisplayString)(kind), 1 /* TEXT */)
]),
_: 2 /* DYNAMIC */
}, 1032 /* PROPS, DYNAMIC_SLOTS */, ["onClick"]);
}), 64 /* STABLE_FRAGMENT */)),
_cache[3] || (_cache[3] = (0, vue_1.createElementVNode)("span", null, "先输入 42,再保持焦点切换类型;前缀按钮的计数应保留。", -1 /* CACHED */))
]),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamAutocomplete), {
modelValue: value.value,
"onUpdate:modelValue": _cache[1] || (_cache[1] = $event => ((value).value = $event)),
type: type.value,
min: 2,
max: 10,
step: 2,
"fetch-suggestions": suggestions,
"trigger-on-focus": false,
"aria-label": "动态输入类型",
onInput: _cache[2] || (_cache[2] = $event => (inputs.value.push($event)))
}, {
prefix: (0, vue_1.withCtx)(() => [
(0, vue_1.createVNode)(SlotCounter_vue_1.default)
]),
_: 1 /* STABLE */
}, 8 /* PROPS */, ["modelValue", "type"]),
(0, vue_1.createElementVNode)("output", null, (0, vue_1.toDisplayString)(JSON.stringify({ type: type.value, value: value.value, inputs: inputs.value })), 1 /* TEXT */),
_cache[4] || (_cache[4] = (0, vue_1.createElementVNode)("p", { class: "example-paragraph" }, " number 的 min/max/step 保留原生约束;切回 text 或 password 后继续编辑。类型切换与光标行为由底层输入处理。number 不支持文本选区,调用文本选区方法可能抛出 InvalidStateError;此入口不补做游标恢复,也不保证未提交编辑值或焦点跨类型保留。 ", -1 /* CACHED */))
]));
};
}
});
exports.default.__scopeId = "data-v-6882299f";
},
"SlotCounter.vue": (module, exports, require) => {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const vue_1 = require("vue");
const ui_1 = require("@asam-ui/ui");
const vue_2 = require("vue");
exports.default = {
__name: 'SlotCounter',
setup(__props) {
const count = (0, vue_2.ref)(0);
return (_ctx, _cache) => {
return ((0, vue_1.openBlock)(), (0, vue_1.createBlock)((0, vue_1.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: _cache[0] || (_cache[0] = $event => (count.value++))
}, {
default: (0, vue_1.withCtx)(() => [
(0, vue_1.createTextVNode)("前缀计数 " + (0, vue_1.toDisplayString)(count.value), 1 /* TEXT */)
]),
_: 1 /* STABLE */
}));
};
}
};
},
};
const __dependencies = {"Demo.vue":{"./SlotCounter.vue":"SlotCounter.vue"},"SlotCounter.vue":{}};
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>
.example[data-v-6882299f] {
display: grid;
gap: var(--asam-space-md);
}
.actions[data-v-6882299f] {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--asam-space-sm);
}
output[data-v-6882299f] {
overflow-wrap: anywhere;
}
p[data-v-6882299f]:where(.example-paragraph) {
margin-block: 16px;
line-height: 1.8;
overflow-wrap: anywhere;
}
</style>
原生委托与事件记录 ​
下方完整 TS/JS 示例记录模型及事件顺序,并可切换禁用、只读和自动校验状态。 完整说明。
原生委托与事件记录
<template>
<section class="native-comparison">
<AsamCheckboxItem v-model="disabled">禁用</AsamCheckboxItem>
<AsamCheckboxItem v-model="readonly">只读</AsamCheckboxItem>
<AsamCheckboxItem v-model="validateEvent">自动校验</AsamCheckboxItem>
<p class="example-paragraph">ASAM</p>
<AsamAutocomplete
v-model="asam"
:disabled="disabled"
:readonly="readonly"
:validate-event="validateEvent"
:fetch-suggestions="suggestions"
:debounce="0"
aria-label="ASAM 原生委托"
@update:model-value="(...args) => record('ASAM', 'update:modelValue', ...args)"
@input="(...args) => record('ASAM', 'input', ...args)"
@change="(...args) => record('ASAM', 'change', ...args)"
@blur="(...args) => record('ASAM', 'blur', ...args)"
/>
<AsamButton type="default" native-type="button" @click="events = []"
>清空事件记录</AsamButton
>
<pre>{{ JSON.stringify({ asam, events }, null, 2) }}</pre>
</section>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import { AsamCheckboxItem, AsamButton, AsamAutocomplete } from '@asam-ui/ui';
defineOptions({ name: 'AsamAutocompleteNativeDelegationExample' });
const asam = ref<string | number>('');
const disabled = ref(false);
const readonly = ref(false);
const validateEvent = ref(true);
const suggestions = [{ value: 'Alpha', label: 'Alpha' }];
const events = ref<{ source: string; event: string; values: unknown[] }[]>([]);
function record(source: string, event: string, ...values: unknown[]) {
events.value.push({
source,
event,
values: values.map((value) => (value instanceof Event ? value.type : value))
});
}
</script>
<style scoped>
.native-comparison {
display: grid;
gap: var(--asam-space-sm);
}
</style>
<style scoped>
p:where(.example-paragraph) {
margin-block: 16px;
line-height: 1.8;
overflow-wrap: anywhere;
}
</style>
<template>
<section class="native-comparison">
<AsamCheckboxItem v-model="disabled">禁用</AsamCheckboxItem>
<AsamCheckboxItem v-model="readonly">只读</AsamCheckboxItem>
<AsamCheckboxItem v-model="validateEvent">自动校验</AsamCheckboxItem>
<p class="example-paragraph">ASAM</p>
<AsamAutocomplete
v-model="asam"
:disabled="disabled"
:readonly="readonly"
:validate-event="validateEvent"
:fetch-suggestions="suggestions"
:debounce="0"
aria-label="ASAM 原生委托"
@update:model-value="(...args) => record('ASAM', 'update:modelValue', ...args)"
@input="(...args) => record('ASAM', 'input', ...args)"
@change="(...args) => record('ASAM', 'change', ...args)"
@blur="(...args) => record('ASAM', 'blur', ...args)"
/>
<AsamButton type="default" native-type="button" @click="events = []"
>清空事件记录</AsamButton
>
<pre>{{ JSON.stringify({ asam, events }, null, 2) }}</pre>
</section>
</template>
<script setup>
import { ref } from 'vue';
import { AsamCheckboxItem, AsamButton, AsamAutocomplete } from '@asam-ui/ui';
defineOptions({ name: 'AsamAutocompleteNativeDelegationExample' });
const asam = ref('');
const disabled = ref(false);
const readonly = ref(false);
const validateEvent = ref(true);
const suggestions = [{ value: 'Alpha', label: 'Alpha' }];
const events = ref([]);
function record(source, event, ...values) {
events.value.push({
source,
event,
values: values.map((value) => (value instanceof Event ? value.type : value))
});
}
</script>
<style scoped>
.native-comparison {
display: grid;
gap: var(--asam-space-sm);
}
</style>
<style scoped>
p:where(.example-paragraph) {
margin-block: 16px;
line-height: 1.8;
overflow-wrap: anywhere;
}
</style>
局部与全局挂载 ​
切换公开挂载参数后,再打开浮层观察内容位于当前组件附近或挂载到 body。 开关显示当前模式,两个模式均可操作;关闭后可以再次切换。
局部与全局挂载
<template>
<div ref="mountTarget" class="popup-stage" :class="{ local: !globalPopup }">
<div class="popup-mode">
<ContainerSwitch
v-model="globalPopup"
active-text="全局挂载到 body"
inactive-text="局部挂载到当前区域"
/>
</div>
<div class="example">
<AsamAutocomplete
v-model="value"
v-bind="{ class: 'field', 'aria-label': '城市补全' }"
:options="options"
:max-suggestions="3"
clearable
@select="(item) => (selected = JSON.stringify(item))"
:teleported="globalPopup"
/>
<output>文本:{{ value }};选项:{{ selected }}</output>
</div>
</div>
</template>
<script lang="ts" setup>
defineOptions({ name: 'AsamAutocompleteOptionsExample' });
import { ref } from 'vue';
import { AsamAutocomplete } from '@asam-ui/ui';
import type { AsamOption } from '@asam-ui/ui';
const value = ref('');
const selected = ref('尚未选择');
const options: AsamOption<string>[] = [
{ value: 'shanghai', label: '上海', raw: { code: 'SH' } },
{ value: 'beijing', label: '北京', raw: { code: 'BJ' } },
{ value: 'closed', label: '停用城市', disabled: true, raw: { code: 'OFF' } }
];
import { ref as containerRef } from 'vue';
import { AsamSwitch as ContainerSwitch } from '@asam-ui/ui';
const globalPopup = containerRef(true);
const mountTarget = containerRef<HTMLElement>();
</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);
}
.field {
width: 100%;
max-width: 360px;
}
output {
overflow-wrap: anywhere;
color: var(--asam-color-text-secondary);
}
</style>
<style scoped>
.popup-stage {
position: relative;
isolation: isolate;
min-height: 140px;
padding: var(--asam-space-md);
border: 1px dashed var(--asam-color-border);
}
.popup-mode {
margin-bottom: var(--asam-space-lg);
}
</style>
<template>
<div ref="mountTarget" class="popup-stage" :class="{ local: !globalPopup }">
<div class="popup-mode">
<ContainerSwitch
v-model="globalPopup"
active-text="全局挂载到 body"
inactive-text="局部挂载到当前区域"
/>
</div>
<div class="example">
<AsamAutocomplete
v-model="value"
v-bind="{ class: 'field', 'aria-label': '城市补全' }"
:options="options"
:max-suggestions="3"
clearable
@select="(item) => (selected = JSON.stringify(item))"
:teleported="globalPopup"
/>
<output>文本:{{ value }};选项:{{ selected }}</output>
</div>
</div>
</template>
<script setup>
defineOptions({ name: 'AsamAutocompleteOptionsExample' });
import { ref } from 'vue';
import { AsamAutocomplete } from '@asam-ui/ui';
const value = ref('');
const selected = ref('尚未选择');
const options = [
{ value: 'shanghai', label: '上海', raw: { code: 'SH' } },
{ value: 'beijing', label: '北京', raw: { code: 'BJ' } },
{ value: 'closed', label: '停用城市', disabled: true, raw: { code: 'OFF' } }
];
import { ref as containerRef } from 'vue';
import { AsamSwitch as ContainerSwitch } from '@asam-ui/ui';
const globalPopup = containerRef(true);
const mountTarget = containerRef();
</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);
}
.field {
width: 100%;
max-width: 360px;
}
output {
overflow-wrap: anywhere;
color: var(--asam-color-text-secondary);
}
</style>
<style scoped>
.popup-stage {
position: relative;
isolation: isolate;
min-height: 140px;
padding: var(--asam-space-md);
border: 1px dashed var(--asam-color-border);
}
.popup-mode {
margin-bottom: var(--asam-space-lg);
}
</style>
API
属性 AsamAutocompleteProps
| 属性名 | 说明 | 类型 | 默认值 |
|---|---|---|---|
modelValue | 字符串或数字输入值。 | string | number | undefined | — |
min | 原生输入的上下界和步长,补充 InputProps 未声明的属性。 | (string | number) | undefined | — |
max | — | (string | number) | undefined | — |
step | — | (string | number) | undefined | — |
options | ASAM 静态选项,按标签筛选并尊重禁用状态。 | readonly AsamOption<V, I>[] | undefined | — |
fetchSuggestions | 原生建议项优先于静态选项。 | AsamAutocompleteFetchSuggestions<T> | undefined | — |
maxSuggestions | ASAM 静态或远程选项的最大建议数;不截断原生建议项。 | number | undefined | — |
remoteSuggestions | 保留 ASAM 选项对象的数据层连接。 | ((query: string) => Promise<readonly AsamOption<V, I>[]>) | undefined | — |
id | 原生 id 能力。 | string | undefined | — |
size | 显式控件密度;省略时保留继承。 | enum"large" | "big" | "default" | "small"完整类型:AsamControlSize | undefined | — |
disabled | 原生 disabled 能力。 | boolean | undefined | false |
modelModifiers | 原生 modelModifiers 能力。 | (AsamAutocompleteProps<V, I, T>)["modelModifiers"] | — |
maxlength | 原生 maxlength 能力。 | string | number | undefined | — |
minlength | 原生 minlength 能力。 | string | number | undefined | — |
type | 原生 type 能力。 | enum"number" | "text" | "email" | "search" | "tel" | "url" | "textarea" | "password"完整类型:(AsamAutocompleteProps<V, I, T>)["type"] | — |
resize | 原生 resize 能力。 | enum"horizontal" | "vertical" | "none" | "both"完整类型:"horizontal" | "vertical" | "none" | "both" | undefined | — |
autosize | 原生 autosize 能力。 | (AsamAutocompleteProps<V, I, T>)["autosize"] | false |
autocomplete | 原生 autocomplete 能力。 | string | undefined | — |
formatter | 原生 formatter 能力。 | ((value: string) => string) | undefined | — |
parser | 原生 parser 能力。 | ((value: string) => string) | undefined | — |
placeholder | 原生 placeholder 能力。 | string | undefined | — |
form | 原生 form 能力。 | string | undefined | — |
readonly | 原生 readonly 能力。 | boolean | undefined | false |
clearable | 原生 clearable 能力。 | boolean | undefined | false |
clearIcon | 原生 clearIcon 能力。 | (AsamAutocompleteProps<V, I, T>)["clearIcon"] | — |
showPassword | 原生 showPassword 能力。 | boolean | undefined | false |
showWordLimit | 原生 showWordLimit 能力。 | boolean | undefined | false |
wordLimitPosition | 原生 wordLimitPosition 能力。 | enum"outside" | "inside"完整类型:"outside" | "inside" | undefined | — |
suffixIcon | 原生 suffixIcon 能力。 | (AsamAutocompleteProps<V, I, T>)["suffixIcon"] | — |
prefixIcon | 原生 prefixIcon 能力。 | (AsamAutocompleteProps<V, I, T>)["prefixIcon"] | — |
containerRole | 原生 containerRole 能力。 | string | undefined | — |
tabindex | 原生 tabindex 能力。 | string | number | undefined | — |
validateEvent | 原生 validateEvent 能力。 | boolean | undefined | false |
inputStyle | 原生 inputStyle 能力。 | import("vue").StyleValue | false |
autofocus | 原生 autofocus 能力。 | boolean | undefined | false |
rows | 原生 rows 能力。 | number | undefined | — |
ariaLabel | 原生 ariaLabel 能力。 | string | undefined | — |
inputmode | 原生 inputmode 能力。 | enum"text" | "email" | "search" | "tel" | "url" | "none" | "numeric" | "decimal"完整类型:"text" | "email" | "search" | "tel" | "url" | "none" | "numeric" | "decimal" | undefined | — |
name | 原生 name 能力。 | string | undefined | — |
countGraphemes | 原生 countGraphemes 能力。 | ((value: string) => number) | undefined | — |
valueKey | 原生 valueKey 能力。 | string | undefined | — |
debounce | 原生 debounce 能力。 | number | undefined | — |
placement | 原生 placement 能力。 | enum"top" | "bottom" | "top-start" | "top-end" | "bottom-start" | "bottom-end"完整类型:(AsamAutocompleteProps<V, I, T>)["placement"] | — |
popperClass | 原生 popperClass 能力。 | AsamAutocompleteProps<V, I, T>["popperClass"] | false |
popperStyle | 原生 popperStyle 能力。 | import("vue").StyleValue | false |
popperOptions | 实际建议面板的 Popper 定位修饰符与配置。 | (AsamAutocompleteProps<V, I, T>)["popperOptions"] | — |
showArrow | 是否显示建议面板箭头,默认 true。 | boolean | undefined | false |
triggerOnFocus | 原生 triggerOnFocus 能力。 | boolean | undefined | false |
selectWhenUnmatched | 原生 selectWhenUnmatched 能力。 | boolean | undefined | false |
hideLoading | 原生 hideLoading 能力。 | boolean | undefined | false |
teleported | 原生 teleported 能力。 | boolean | undefined | false |
appendTo | 原生 appendTo 能力。 | string | HTMLElement | undefined | — |
highlightFirstItem | 原生 highlightFirstItem 能力。 | boolean | undefined | false |
fitInputWidth | 原生 fitInputWidth 能力。 | boolean | undefined | false |
loopNavigation | 原生 loopNavigation 能力。 | boolean | undefined | false |
事件 AsamAutocompleteEmits
| 属性名 | 说明 | 类型 | 默认值 |
|---|---|---|---|
update:modelValue | — | [value: string | number] | — |
input | — | [value: string | number] | — |
change | — | [value: string | number] | — |
select | 匹配到的原建议项,或原生未匹配时按 Enter 返回的纯 value 数据。 | [item: T | AsamOption<V, I> | { value: string | number; }] | — |
clear | — | (AsamAutocompleteEmits<V, I, T>)["clear"] | — |
focus | — | [event: FocusEvent] | — |
blur | — | [event: FocusEvent] | — |
compositionstart | — | [event: CompositionEvent] | — |
compositionupdate | — | [event: CompositionEvent] | — |
compositionend | — | [event: CompositionEvent] | — |
mouseenter | — | [event: MouseEvent] | — |
mouseleave | — | [event: MouseEvent] | — |
keydown | — | [event: Event | KeyboardEvent] | — |
插槽 AsamAutocompleteSlots
| 属性名 | 说明 | 类型 | 默认值 |
|---|---|---|---|
default | — | ((props: { item: T | AsamOption<V, I>; }) => unknown) | undefined | — |
prefix | — | (() => unknown) | undefined | — |
suffix | — | (() => unknown) | undefined | — |
prepend | — | (() => unknown) | undefined | — |
append | — | (() => unknown) | undefined | — |
header | — | (() => unknown) | undefined | — |
footer | — | (() => unknown) | undefined | — |
loading | — | (() => unknown) | undefined | — |
实例方法与状态 AsamAutocompleteExpose
| 属性名 | 说明 | 类型 | 默认值 |
|---|---|---|---|
highlightedIndex | — | number | — |
activated | — | boolean | — |
loading | — | boolean | — |
inputRef | — | (AsamAutocompleteExpose<T>)["inputRef"] | — |
popperRef | — | (AsamAutocompleteExpose<T>)["popperRef"] | — |
suggestions | — | T[] | — |
focus | — | () => void | — |
blur | — | () => void | — |
close | — | () => void | — |
highlight | — | (index: number) => void | — |
getData | — | (query: string) => Promise<void> | — |
handleSelect | — | (item: T) => Promise<void> | — |
handleKeyEnter | — | () => Promise<void> | — |
用法与契约补充说明 ​
ASAM 扩展与迁移 ​
ASAM 扩展是 options、maxSuggestions 与原对象回传。remoteSuggestions 是数据层桥接,应用远程/provider 能力使用本站 RemoteAutocomplete。密码和普通多行文本分别使用 Password、Textarea。省略 size 保留四档继承,建议面板参数按本页完整 API 配置。
异步建议与键盘提交 ​
fetchSuggestions 支持数组、回调、同步数组或 Promise;设置它时优先于 ASAM options/remoteSuggestions,原生建议不会被 maxSuggestions 截断。ASAM 静态 options 过滤 label/disabled,选中后的字符串模型是 label,select 保留原选项及扩展字段。远程数据包装见 AsamRemoteAutocomplete。
异步建议与键盘提交 ​
debounce 控制查询防抖,triggerOnFocus 控制聚焦查询,highlightFirstItem 高亮首项,loopNavigation 决定方向键是否环绕。selectWhenUnmatched 为 true 时,没有高亮匹配候选的 Enter 会发出 { value: modelValue };value 保留 string 或 number,即使自定义 valueKey 也仍使用 value 字段,不补造 label、raw 或业务字段。false 或省略时不发出这种 select。真实 Enter 和实例 handleKeyEnter 遵循同一协议;loading 插槽可替换加载标记。header/footer/default 展示列表附加内容和完整候选。
异步建议与键盘提交 ​
select 的类型为 T | AsamOption<V, I> | { value: string | number }。消费方访问 label/raw 或自定义字段前,先按字段存在性收窄:'label' in item 承接完整 ASAM 选项,'id' in item 承接示例的完整原生建议,其余分支只读取 value。下方完整 TS/JS 示例同时展示匹配原对象与未匹配最小载荷,输入“自由输入”后等待空建议再按 Enter。
完整继承输入组合 ​
min/max/step、formatter/parser、modelModifiers 与 textarea 参数原样交给 底层输入。原生分支只在未配置 options/remoteSuggestions,或已提供 fetchSuggestions 时使用;该分支不增加 placeholder、debounce 或 valueKey 默认值。省略 fetchSuggestions 后要获取建议,须先提供原生数组或函数;原生缺少建议源时的查询限制保持。
完整继承输入组合 ​
ASAM options/remoteSuggestions 分支继续按 label 过滤、忽略 disabled 项并保留原选项对象与 maxSuggestions 上限。两分支的输入、lazy、密码显隐、表单 change/blur 校验都由原生输入处理;ASAM 不保存独立草稿、不自动补交、不去重或强制恢复父级模型。
继承输入事件 ​
compositionstart、compositionupdate、compositionend 的参数均为 CompositionEvent,携带输入合成数据。mouseenter、mouseleave 的参数为 MouseEvent;keydown 接受 KeyboardEvent | Event,保留原生输入分支的 Event 边界。这六类事件从实际输入转发,每个实际事件通知一次;键盘监听保留内部方向键高亮和 Enter 选择逻辑。focus、blur 继续携带 FocusEvent;input/change 携带模型值,select 携带完整匹配候选或上述未匹配 value-only 载荷。
原生委托与事件记录 ​
下方完整 TS/JS 示例记录模型及事件顺序,并可切换禁用、只读和自动校验状态。省略的基础参数使用原生 defaults;显式 undefined/null/false 原样传入,合法值范围见 API。四档 size 是 ASAM 的视觉桥接;Password 额外固定 type=password,并在省略 showPassword 时启用显隐入口。
关联组件
参数与事件补充说明
参数与事件说明
modelValue
必填:否;声明来源:ASAM 声明。
min
必填:否;声明来源:ASAM 声明。
max
必填:否;声明来源:ASAM 声明。
step
必填:否;声明来源:ASAM 声明。
options
必填:否;声明来源:ASAM 声明。
fetchSuggestions
必填:否;声明来源:ASAM 声明。
fetchSuggestions 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(query: string, callback: (items: T[]) => void): void | T[] | Promise<void | T[]>
maxSuggestions
必填:否;声明来源:ASAM 声明。
remoteSuggestions
必填:否;声明来源:ASAM 声明。
remoteSuggestions 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(query: string): Promise<readonly AsamOption<V, I>[]>
id
必填:否;声明来源:ASAM 声明。
默认值与来源
未知 / 未声明固定上游源码默认表达式:undefined(2.14.7;源码事实,未作为 ASAM 运行实测)
size
必填:否;声明来源:ASAM 声明。
size 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:"large" / "big" / "default" / "small"
disabled
必填:否;声明来源:ASAM 声明。
disabled 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
默认值与来源
false(隐式 Boolean 默认;已安装组件)固定上游文档默认:false(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:undefined(2.14.7;源码事实,未作为 ASAM 运行实测)
modelModifiers
必填:否;声明来源:ASAM 声明。
modelModifiers 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
modelModifiers.lazy:true | undefined— 上游声明枚举:
truemodelModifiers.number:true | undefined— 上游声明枚举:
truemodelModifiers.trim:true | undefined— 上游声明枚举:
true
默认值与来源
未知 / 未声明固定上游文档默认:未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码工厂(未执行):() => ({})(2.14.7;源码事实,未作为 ASAM 运行实测)
maxlength
必填:否;声明来源:ASAM 声明。
默认值与来源
未知 / 未声明固定上游文档默认:未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码未声明 default(2.14.7;源码事实,未作为 ASAM 运行实测)
minlength
必填:否;声明来源:ASAM 声明。
默认值与来源
未知 / 未声明固定上游文档默认:未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码未声明 default(2.14.7;源码事实,未作为 ASAM 运行实测)
type
必填:否;声明来源:ASAM 声明。
type 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:"number" / "text" / "email" / "search" / "tel" / "url" / "textarea" / "password"
默认值与来源
未知 / 未声明固定上游文档默认:text(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:'text'(2.14.7;源码事实,未作为 ASAM 运行实测)
resize
必填:否;声明来源:ASAM 声明。
resize 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:"horizontal" / "vertical" / "none" / "both"
默认值与来源
未知 / 未声明固定上游文档默认:未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码未声明 default(2.14.7;源码事实,未作为 ASAM 运行实测)
autosize
必填:否;声明来源:ASAM 声明。
autosize 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
autosize.minRows:number | undefined— 上游声明autosize.maxRows:number | undefined— 上游声明
默认值与来源
false(隐式 Boolean 默认;已安装组件)固定上游文档默认:false(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:false(2.14.7;源码事实,未作为 ASAM 运行实测)
autocomplete
必填:否;声明来源:ASAM 声明。
默认值与来源
未知 / 未声明固定上游文档默认:off(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:'off'(2.14.7;源码事实,未作为 ASAM 运行实测)
formatter
必填:否;声明来源:ASAM 声明。
formatter 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(value: string): string
默认值与来源
未知 / 未声明固定上游文档默认:未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码未声明 default(2.14.7;源码事实,未作为 ASAM 运行实测)
parser
必填:否;声明来源:ASAM 声明。
parser 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(value: string): string
默认值与来源
未知 / 未声明固定上游文档默认:未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码未声明 default(2.14.7;源码事实,未作为 ASAM 运行实测)
placeholder
必填:否;声明来源:ASAM 声明。
默认值与来源
未知 / 未声明固定上游文档默认:未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码未声明 default(2.14.7;源码事实,未作为 ASAM 运行实测)
form
必填:否;声明来源:ASAM 声明。
默认值与来源
未知 / 未声明固定上游文档默认:未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码未声明 default(2.14.7;源码事实,未作为 ASAM 运行实测)
readonly
必填:否;声明来源:ASAM 声明。
readonly 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
默认值与来源
false(隐式 Boolean 默认;已安装组件)固定上游文档默认:false(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
clearable
必填:否;声明来源:ASAM 声明。
clearable 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
默认值与来源
false(隐式 Boolean 默认;已安装组件)固定上游文档默认:false(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
clearIcon
必填:否;声明来源:ASAM 声明。
clearIcon 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(props: any, ctx: Parameters<Extract<NonNullable<(AsamAutocompleteProps<V, I, T>)["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 运行实测)
showPassword
必填:否;声明来源:ASAM 声明。
showPassword 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
默认值与来源
false(隐式 Boolean 默认;已安装组件)固定上游文档默认:false(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
showWordLimit
必填:否;声明来源:ASAM 声明。
showWordLimit 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
默认值与来源
false(隐式 Boolean 默认;已安装组件)固定上游文档默认:false(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
wordLimitPosition
必填:否;声明来源:ASAM 声明。
wordLimitPosition 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:"outside" / "inside"
默认值与来源
未知 / 未声明固定上游文档默认:"inside"(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:'inside'(2.14.7;源码事实,未作为 ASAM 运行实测)
suffixIcon
必填:否;声明来源:ASAM 声明。
suffixIcon 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(props: any, ctx: Parameters<Extract<NonNullable<(AsamAutocompleteProps<V, I, T>)["suffixIcon"]>, (...args: never[]) => unknown>>[1]): any
suffixIcon.__isFragment:undefined— 依赖声明suffixIcon.__isTeleport:undefined— 依赖声明suffixIcon.__isSuspense:undefined— 依赖声明
默认值与来源
未知 / 未声明固定上游文档默认:未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码未声明 default(2.14.7;源码事实,未作为 ASAM 运行实测)
prefixIcon
必填:否;声明来源:ASAM 声明。
prefixIcon 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(props: any, ctx: Parameters<Extract<NonNullable<(AsamAutocompleteProps<V, I, T>)["prefixIcon"]>, (...args: never[]) => unknown>>[1]): any
prefixIcon.__isFragment:undefined— 依赖声明prefixIcon.__isTeleport:undefined— 依赖声明prefixIcon.__isSuspense:undefined— 依赖声明
默认值与来源
未知 / 未声明固定上游文档默认:未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码未声明 default(2.14.7;源码事实,未作为 ASAM 运行实测)
containerRole
必填:否;声明来源:ASAM 声明。
默认值与来源
未知 / 未声明固定上游源码默认表达式:undefined(2.14.7;源码事实,未作为 ASAM 运行实测)
tabindex
必填:否;声明来源:ASAM 声明。
默认值与来源
未知 / 未声明固定上游文档默认:未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:0(2.14.7;源码事实,未作为 ASAM 运行实测)
validateEvent
必填:否;声明来源:ASAM 声明。
validateEvent 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
默认值与来源
false(隐式 Boolean 默认;已安装组件)固定上游文档默认:true(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:true(2.14.7;源码事实,未作为 ASAM 运行实测)
inputStyle
必填:否;声明来源:ASAM 声明。
inputStyle 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false
嵌套展开边界:框架 / 平台类型;完整类型见公开类型视图。
默认值与来源
false(隐式 Boolean 默认;已安装组件)固定上游文档默认:{}(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码工厂(未执行):() => mutable({} as const)(2.14.7;源码事实,未作为 ASAM 运行实测)
autofocus
必填:否;声明来源:ASAM 声明。
autofocus 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
默认值与来源
false(隐式 Boolean 默认;已安装组件)固定上游文档默认:false(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
rows
必填:否;声明来源:ASAM 声明。
默认值与来源
未知 / 未声明固定上游文档默认:2(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:2(2.14.7;源码事实,未作为 ASAM 运行实测)
ariaLabel
必填:否;声明来源:ASAM 声明。
默认值与来源
未知 / 未声明固定上游文档默认:未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
inputmode
必填:否;声明来源:ASAM 声明。
inputmode 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:"text" / "email" / "search" / "tel" / "url" / "none" / "numeric" / "decimal"
默认值与来源
未知 / 未声明固定上游文档默认:未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:undefined(2.14.7;源码事实,未作为 ASAM 运行实测)
name
必填:否;声明来源:ASAM 声明。
默认值与来源
未知 / 未声明固定上游文档默认:未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
countGraphemes
必填:否;声明来源:ASAM 声明。
countGraphemes 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(value: string): number
默认值与来源
未知 / 未声明固定上游文档默认:未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码未声明 default(2.14.7;源码事实,未作为 ASAM 运行实测)
valueKey
必填:否;声明来源:ASAM 声明。
默认值与来源
未知 / 未声明固定上游文档默认:value(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:'value'(2.14.7;源码事实,未作为 ASAM 运行实测)
debounce
必填:否;声明来源:ASAM 声明。
默认值与来源
未知 / 未声明固定上游文档默认:300(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:300(2.14.7;源码事实,未作为 ASAM 运行实测)
placement
必填:否;声明来源:ASAM 声明。
placement 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:"top" / "bottom" / "top-start" / "top-end" / "bottom-start" / "bottom-end"
默认值与来源
未知 / 未声明固定上游文档默认:bottom-start(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:'bottom-start'(2.14.7;源码事实,未作为 ASAM 运行实测)
popperClass
必填:否;声明来源:ASAM 声明。
popperClass 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false
默认值与来源
false(隐式 Boolean 默认;已安装组件)固定上游文档默认:''(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
popperStyle
必填:否;声明来源:ASAM 声明。
popperStyle 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false
嵌套展开边界:框架 / 平台类型;完整类型见公开类型视图。
默认值与来源
false(隐式 Boolean 默认;已安装组件)固定上游文档默认:未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
popperOptions
必填:否;声明来源:ASAM 声明。
popperOptions 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
popperOptions.placement:PublicMember<NonNullable<(AsamAutocompleteProps<V, I, T>)["popperOptions"]>, "placement">— 依赖声明枚举:
"auto"/"auto-start"/"auto-end"/"top"/"bottom"/"right"/"left"/"top-start"/"top-end"/"bottom-start"/"bottom-end"/"right-start"/"right-end"/"left-start"/"left-end"popperOptions.modifiers:PublicMember<NonNullable<(AsamAutocompleteProps<V, I, T>)["popperOptions"]>, "modifiers">— 依赖声明popperOptions.strategy:PublicMember<NonNullable<(AsamAutocompleteProps<V, I, T>)["popperOptions"]>, "strategy">— 依赖声明枚举:
"fixed"/"absolute"popperOptions.onFirstUpdate:PublicMember<NonNullable<(AsamAutocompleteProps<V, I, T>)["popperOptions"]>, "onFirstUpdate">— 依赖声明事件参数:
(arg0: Parameters<Extract<NonNullable<PublicMember<NonNullable<(AsamAutocompleteProps<V, I, T>)["popperOptions"]>, "onFirstUpdate">>, (...args: never[]) => unknown>>[0]): void
默认值与来源
未知 / 未声明固定上游文档默认:{}(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
showArrow
必填:否;声明来源:ASAM 声明。
showArrow 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
默认值与来源
false(隐式 Boolean 默认;已安装组件)固定上游文档默认:true(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:true(2.14.7;源码事实,未作为 ASAM 运行实测)
triggerOnFocus
必填:否;声明来源:ASAM 声明。
triggerOnFocus 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
默认值与来源
false(隐式 Boolean 默认;已安装组件)固定上游文档默认:true(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:true(2.14.7;源码事实,未作为 ASAM 运行实测)
selectWhenUnmatched
必填:否;声明来源:ASAM 声明。
selectWhenUnmatched 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
默认值与来源
false(隐式 Boolean 默认;已安装组件)固定上游文档默认:false(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
hideLoading
必填:否;声明来源:ASAM 声明。
hideLoading 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
默认值与来源
false(隐式 Boolean 默认;已安装组件)固定上游文档默认:false(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
teleported
必填:否;声明来源:ASAM 声明。
teleported 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
默认值与来源
false(隐式 Boolean 默认;已安装组件)固定上游文档默认:true(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
appendTo
必填:否;声明来源:ASAM 声明。
appendTo 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
嵌套展开边界:大型实例类型;完整类型见公开类型视图。
默认值与来源
未知 / 未声明固定上游文档默认:未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
highlightFirstItem
必填:否;声明来源:ASAM 声明。
highlightFirstItem 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
默认值与来源
false(隐式 Boolean 默认;已安装组件)固定上游文档默认:false(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
fitInputWidth
必填:否;声明来源:ASAM 声明。
fitInputWidth 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
默认值与来源
false(隐式 Boolean 默认;已安装组件)固定上游文档默认:false(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
loopNavigation
必填:否;声明来源:ASAM 声明。
loopNavigation 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
默认值与来源
false(隐式 Boolean 默认;已安装组件)固定上游文档默认:true(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:true(2.14.7;源码事实,未作为 ASAM 运行实测)
AsamAutocompleteProps 公开类型视图
import type { Attrs } from 'vue';
import type { AsamAutocompleteProps, AsamValue, AsamRecord, AsamOption, AsamAutocompleteFetchSuggestions, AsamControlSize } from '@asam-ui/ui';
type PublicMember<T, K extends PropertyKey> = T extends unknown ? K extends keyof T ? T[K] : never : never;
// AsamAutocompleteProps
type PublicContract<V extends AsamValue = AsamValue, I extends object = AsamRecord, T extends object = AsamOption<V, I>> = {
readonly "modelValue"?: string | number | undefined;
readonly "min"?: (string | number) | undefined;
readonly "max"?: (string | number) | undefined;
readonly "step"?: (string | number) | undefined;
readonly "options"?: readonly AsamOption<V, I>[] | undefined;
readonly "fetchSuggestions"?: AsamAutocompleteFetchSuggestions<T> | undefined;
readonly "maxSuggestions"?: number | undefined;
readonly "remoteSuggestions"?: ((query: string) => Promise<readonly AsamOption<V, I>[]>) | undefined;
readonly "id"?: string | undefined;
readonly "size"?: AsamControlSize | undefined;
readonly "disabled"?: boolean | undefined;
readonly "modelModifiers"?: (AsamAutocompleteProps<V, I, T>)["modelModifiers"];
readonly "maxlength"?: string | number | undefined;
readonly "minlength"?: string | number | undefined;
readonly "type"?: (AsamAutocompleteProps<V, I, T>)["type"];
readonly "resize"?: "horizontal" | "vertical" | "none" | "both" | undefined;
readonly "autosize"?: (AsamAutocompleteProps<V, I, T>)["autosize"];
readonly "autocomplete"?: string | undefined;
readonly "formatter"?: ((value: string) => string) | undefined;
readonly "parser"?: ((value: string) => string) | undefined;
readonly "placeholder"?: string | undefined;
readonly "form"?: string | undefined;
readonly "readonly"?: boolean | undefined;
readonly "clearable"?: boolean | undefined;
readonly "clearIcon"?: (AsamAutocompleteProps<V, I, T>)["clearIcon"];
readonly "showPassword"?: boolean | undefined;
readonly "showWordLimit"?: boolean | undefined;
readonly "wordLimitPosition"?: "outside" | "inside" | undefined;
readonly "suffixIcon"?: (AsamAutocompleteProps<V, I, T>)["suffixIcon"];
readonly "prefixIcon"?: (AsamAutocompleteProps<V, I, T>)["prefixIcon"];
readonly "containerRole"?: string | undefined;
readonly "tabindex"?: string | number | undefined;
readonly "validateEvent"?: boolean | undefined;
readonly "inputStyle"?: import("vue").StyleValue;
readonly "autofocus"?: boolean | undefined;
readonly "rows"?: number | undefined;
readonly "ariaLabel"?: string | undefined;
readonly "inputmode"?: "text" | "email" | "search" | "tel" | "url" | "none" | "numeric" | "decimal" | undefined;
readonly "name"?: string | undefined;
readonly "countGraphemes"?: ((value: string) => number) | undefined;
readonly "valueKey"?: string | undefined;
readonly "debounce"?: number | undefined;
readonly "placement"?: (AsamAutocompleteProps<V, I, T>)["placement"];
readonly "popperClass"?: AsamAutocompleteProps<V, I, T>["popperClass"];
readonly "popperStyle"?: import("vue").StyleValue;
readonly "popperOptions"?: (AsamAutocompleteProps<V, I, T>)["popperOptions"];
readonly "showArrow"?: boolean | undefined;
readonly "triggerOnFocus"?: boolean | undefined;
readonly "selectWhenUnmatched"?: boolean | undefined;
readonly "hideLoading"?: boolean | undefined;
readonly "teleported"?: boolean | undefined;
readonly "appendTo"?: string | HTMLElement | undefined;
readonly "highlightFirstItem"?: boolean | undefined;
readonly "fitInputWidth"?: boolean | undefined;
readonly "loopNavigation"?: boolean | undefined;
};
参数与事件说明
update:modelValue
必填:是;声明来源:ASAM 声明。
input
必填:是;声明来源:ASAM 声明。
change
必填:是;声明来源:ASAM 声明。
select
必填:是;声明来源:ASAM 声明。
clear
必填:是;声明来源:ASAM 声明。
focus
必填:是;声明来源:ASAM 声明。
blur
必填:是;声明来源:ASAM 声明。
compositionstart
必填:是;声明来源:ASAM 声明。
compositionupdate
必填:是;声明来源:ASAM 声明。
compositionend
必填:是;声明来源:ASAM 声明。
mouseenter
必填:是;声明来源:ASAM 声明。
mouseleave
必填:是;声明来源:ASAM 声明。
keydown
必填:是;声明来源:ASAM 声明。
AsamAutocompleteEmits 公开类型视图
import type { AsamAutocompleteEmits, AsamValue, AsamOption } from '@asam-ui/ui';
// AsamAutocompleteEmits
type PublicContract<V extends AsamValue = AsamValue, I extends object = object, T extends object = AsamOption<V, I>> = {
"update:modelValue": [value: string | number];
"input": [value: string | number];
"change": [value: string | number];
"select": [item: T | AsamOption<V, I> | { value: string | number; }];
"clear": (AsamAutocompleteEmits<V, I, T>)["clear"];
"focus": [event: FocusEvent];
"blur": [event: FocusEvent];
"compositionstart": [event: CompositionEvent];
"compositionupdate": [event: CompositionEvent];
"compositionend": [event: CompositionEvent];
"mouseenter": [event: MouseEvent];
"mouseleave": [event: MouseEvent];
"keydown": [event: Event | KeyboardEvent];
};
参数与事件说明
default
必填:否;声明来源:ASAM 声明。
default 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(props: { item: T | AsamOption<V, I>; }): unknown
prefix
必填:否;声明来源:ASAM 声明。
prefix 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(): unknown
suffix
必填:否;声明来源:ASAM 声明。
suffix 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(): unknown
prepend
必填:否;声明来源:ASAM 声明。
prepend 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(): unknown
append
必填:否;声明来源:ASAM 声明。
append 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(): unknown
header
必填:否;声明来源:ASAM 声明。
header 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(): unknown
footer
必填:否;声明来源:ASAM 声明。
footer 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(): unknown
loading
必填:否;声明来源:ASAM 声明。
loading 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(): unknown
AsamAutocompleteSlots 公开类型视图
import type { AsamAutocompleteSlots, AsamValue, AsamOption } from '@asam-ui/ui';
// AsamAutocompleteSlots
type PublicContract<V extends AsamValue = AsamValue, I extends object = object, T extends object = AsamOption<V, I>> = {
"default"?: ((props: { item: T | AsamOption<V, I>; }) => unknown) | undefined;
"prefix"?: (() => unknown) | undefined;
"suffix"?: (() => unknown) | undefined;
"prepend"?: (() => unknown) | undefined;
"append"?: (() => unknown) | undefined;
"header"?: (() => unknown) | undefined;
"footer"?: (() => unknown) | undefined;
"loading"?: (() => unknown) | undefined;
};
实时状态与异步实例操作。
参数与事件说明
highlightedIndex
必填:是;声明来源:ASAM 声明。
activated
必填:是;声明来源:ASAM 声明。
activated 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
loading
必填:是;声明来源:ASAM 声明。
loading 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
inputRef
必填:是;声明来源:ASAM 声明。
popperRef
必填:是;声明来源:ASAM 声明。
suggestions
必填:是;声明来源:ASAM 声明。
suggestions 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
嵌套展开边界:框架 / 平台类型;完整类型见公开类型视图。
focus
必填:是;声明来源:ASAM 声明。
focus 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(): void
blur
必填:是;声明来源:ASAM 声明。
blur 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(): void
close
必填:是;声明来源:ASAM 声明。
close 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(): void
highlight
必填:是;声明来源:ASAM 声明。
highlight 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(index: number): void
getData
必填:是;声明来源:ASAM 声明。
getData 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(query: string): Promise<void>
handleSelect
必填:是;声明来源:ASAM 声明。
handleSelect 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(item: T): Promise<void>
handleKeyEnter
必填:是;声明来源:ASAM 声明。
handleKeyEnter 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(): Promise<void>
AsamAutocompleteExpose 公开类型视图
import type { AsamAutocompleteExpose, AsamRecord } from '@asam-ui/ui';
// AsamAutocompleteExpose
type PublicContract<T extends object = AsamRecord> = {
readonly "highlightedIndex": number;
readonly "activated": boolean;
readonly "loading": boolean;
readonly "inputRef": (AsamAutocompleteExpose<T>)["inputRef"];
readonly "popperRef": (AsamAutocompleteExpose<T>)["popperRef"];
readonly "suggestions": T[];
"focus": () => void;
"blur": () => void;
"close": () => void;
"highlight": (index: number) => void;
"getData": (query: string) => Promise<void>;
"handleSelect": (item: T) => Promise<void>;
"handleKeyEnter": () => Promise<void>;
};