使用场景 ​
用于评论、消息中的 @人员、#主题等提及,模型保存完整输入内容。 完整说明。
触发与选择 ​
输入 @ 后显示候选。select 同时返回选项与触发字符,search 返回检索片段与字符。
触发与选择
<template>
<div class="example">
<AsamMention
v-model="value"
v-bind="{ class: 'field', 'aria-label': '评论提及' }"
:options="options"
@select="(item, prefix) => (selected = prefix + item.label)"
@search="(pattern, prefix) => (query = prefix + pattern)"
/>
<output>评论:{{ value }};选择:{{ selected }};检索:{{ query }}</output>
</div>
</template>
<script lang="ts" setup>
defineOptions({ name: 'AsamMentionBasicExample' });
import { ref } from 'vue';
import { AsamMention } from '@asam-ui/ui';
import type { AsamMentionOption } from '@asam-ui/ui';
const value = ref('');
const selected = ref('');
const query = ref('');
const options: AsamMentionOption[] = [
{ value: 'design', label: '设计组' },
{ value: 'dev', label: '开发组' },
{ value: 'disabled', label: '停用组', disabled: true }
];
</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">
<AsamMention
v-model="value"
v-bind="{ class: 'field', 'aria-label': '评论提及' }"
:options="options"
@select="(item, prefix) => (selected = prefix + item.label)"
@search="(pattern, prefix) => (query = prefix + pattern)"
/>
<output>评论:{{ value }};选择:{{ selected }};检索:{{ query }}</output>
</div>
</template>
<script setup>
defineOptions({ name: 'AsamMentionBasicExample' });
import { ref } from 'vue';
import { AsamMention } from '@asam-ui/ui';
const value = ref('');
const selected = ref('');
const query = ref('');
const options = [
{ value: 'design', label: '设计组' },
{ value: 'dev', label: '开发组' },
{ value: 'disabled', label: '停用组', disabled: true }
];
</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>
多触发字符与自定义标签 ​
prefix 可使用一个字符或字符数组,每项必须恰好一个字符;split 也必须是单字符。label 插槽接收 item、index。
多触发字符与自定义标签
<template>
<div class="example">
<AsamMention
v-model="value"
v-bind="{ class: 'field', 'aria-label': '人员主题提及' }"
:options="options"
:prefix="['@', '#']"
split=" "
whole
@whole-remove="(pattern, prefix) => (removed = prefix + pattern)"
>
<template #label="{ item, index }"> {{ index + 1 }} · {{ item.label }} </template>
<template #header> 选择人员或主题 </template>
<template #footer> 支持 @ 和 # </template>
</AsamMention>
<output>整项删除:{{ removed }}</output>
</div>
</template>
<script lang="ts" setup>
defineOptions({ name: 'AsamMentionCustomExample' });
import { ref } from 'vue';
import { AsamMention } from '@asam-ui/ui';
const value = ref('');
const removed = ref('');
const options = [
{ value: 'asam', label: 'ASAM 主题' },
{ value: 'team', label: '协作小组' }
];
</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">
<AsamMention
v-model="value"
v-bind="{ class: 'field', 'aria-label': '人员主题提及' }"
:options="options"
:prefix="['@', '#']"
split=" "
whole
@whole-remove="(pattern, prefix) => (removed = prefix + pattern)"
>
<template #label="{ item, index }"> {{ index + 1 }} · {{ item.label }} </template>
<template #header> 选择人员或主题 </template>
<template #footer> 支持 @ 和 # </template>
</AsamMention>
<output>整项删除:{{ removed }}</output>
</div>
</template>
<script setup>
defineOptions({ name: 'AsamMentionCustomExample' });
import { ref } from 'vue';
import { AsamMention } from '@asam-ui/ui';
const value = ref('');
const removed = ref('');
const options = [
{ value: 'asam', label: 'ASAM 主题' },
{ value: 'team', label: '协作小组' }
];
</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>
多行提及与公开状态 ​
提及场景自身支持 textarea 类型和 autosize;普通多行文本请使用专用 Textarea。实例公开 input、tooltip、dropdownVisible。
多行提及与公开状态
<!-- 此演示还使用 @asam-ui/icons-vue,请按官网对应指南配置这些公开依赖。 -->
<template>
<div class="example">
<AsamMention
ref="mention"
v-model="value"
v-bind="{ class: 'field', 'aria-label': '多行评论' }"
type="textarea"
:rows="3"
:autosize="{ minRows: 3, maxRows: 5 }"
:options="options"
>
<template #prefix>
<ChatDotRound style="width: 16px" />
</template>
</AsamMention>
<AsamButton type="default" @click="visible = mention?.dropdownVisible ?? false">
读取提及面板状态
</AsamButton>
<output>面板可见:{{ visible }}</output>
</div>
</template>
<script lang="ts" setup>
defineOptions({ name: 'AsamMentionMultilineExample' });
import { ref } from 'vue';
import { AsamMention, AsamButton } from '@asam-ui/ui';
import type { AsamMentionExpose } from '@asam-ui/ui';
import { ChatDotRound } from '@asam-ui/icons-vue';
const mention = ref<AsamMentionExpose>();
const value = ref('');
const visible = ref(false);
const options = [
{ value: 'design', label: '设计组' },
{ value: 'dev', label: '开发组' }
];
</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-ui/icons-vue,请按官网对应指南配置这些公开依赖。 -->
<template>
<div class="example">
<AsamMention
ref="mention"
v-model="value"
v-bind="{ class: 'field', 'aria-label': '多行评论' }"
type="textarea"
:rows="3"
:autosize="{ minRows: 3, maxRows: 5 }"
:options="options"
>
<template #prefix>
<ChatDotRound style="width: 16px" />
</template>
</AsamMention>
<AsamButton type="default" @click="visible = mention?.dropdownVisible ?? false">
读取提及面板状态
</AsamButton>
<output>面板可见:{{ visible }}</output>
</div>
</template>
<script setup>
defineOptions({ name: 'AsamMentionMultilineExample' });
import { ref } from 'vue';
import { AsamMention, AsamButton } from '@asam-ui/ui';
import { ChatDotRound } from '@asam-ui/icons-vue';
const mention = ref();
const value = ref('');
const visible = ref(false);
const options = [
{ value: 'design', label: '设计组' },
{ value: 'dev', label: '开发组' }
];
</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>
四档密度与继承 ​
large / big / default / small 分别为四档密度。显式 size 覆盖继承;省略 size 时按组件、组、表单、ConfigProvider 到 default 解析。通过切换 provider 验证继承响应。
四档密度与继承
<template>
<div class="example">
<div class="row">
<AsamMention
size="large"
v-bind="{ class: 'field', 'aria-label': 'large尺寸' }"
model-value="@team"
:options="[{ value: 'team', label: '协作组' }]"
/>
<AsamMention
size="big"
v-bind="{ class: 'field', 'aria-label': 'big尺寸' }"
model-value="@team"
:options="[{ value: 'team', label: '协作组' }]"
/>
<AsamMention
size="default"
v-bind="{ class: 'field', 'aria-label': 'default尺寸' }"
model-value="@team"
:options="[{ value: 'team', label: '协作组' }]"
/>
<AsamMention
size="small"
v-bind="{ class: 'field', 'aria-label': 'small尺寸' }"
model-value="@team"
:options="[{ value: 'team', label: '协作组' }]"
/>
</div>
<AsamConfigProvider :size="density">
<div class="example">
<AsamMention
v-bind="{ class: 'field', 'aria-label': '继承尺寸' }"
model-value="@team"
:options="[{ value: 'team', label: '协作组' }]"
/>
<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: 'AsamMentionSizesExample' });
import { ref } from 'vue';
import { AsamMention, 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">
<AsamMention
size="large"
v-bind="{ class: 'field', 'aria-label': 'large尺寸' }"
model-value="@team"
:options="[{ value: 'team', label: '协作组' }]"
/>
<AsamMention
size="big"
v-bind="{ class: 'field', 'aria-label': 'big尺寸' }"
model-value="@team"
:options="[{ value: 'team', label: '协作组' }]"
/>
<AsamMention
size="default"
v-bind="{ class: 'field', 'aria-label': 'default尺寸' }"
model-value="@team"
:options="[{ value: 'team', label: '协作组' }]"
/>
<AsamMention
size="small"
v-bind="{ class: 'field', 'aria-label': 'small尺寸' }"
model-value="@team"
:options="[{ value: 'team', label: '协作组' }]"
/>
</div>
<AsamConfigProvider :size="density">
<div class="example">
<AsamMention
v-bind="{ class: 'field', 'aria-label': '继承尺寸' }"
model-value="@team"
:options="[{ value: 'team', label: '协作组' }]"
/>
<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: 'AsamMentionSizesExample' });
import { ref } from 'vue';
import { AsamMention, 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 四档 size 继承适用于提及控件。whole/checkIsWhole 控制退格整项删除,filterOption 可自定义检索,props 可映射自定义选项字段;loading/loading 插槽由应用驱动。密码职责见 Password,普通单行和多行分别见 Input、Textarea。
选项字段映射与异步加载 ​
props 映射 value/label/disabled 字段,select 返回原始选项。应用维护 options/loading;未配置 filterOption 时按 label 或 value 默认过滤,显式 false 关闭过滤。远程结果应丢弃过期请求;loading 插槽展示加载状态。
应用异步选项与字段映射
<template>
<div class="example">
<AsamMention
v-model="value"
:options="options"
:props="{ value: 'id', label: 'name', disabled: 'inactive' }"
:loading="loading"
:filter-option="false"
aria-label="异步人员"
@search="search"
>
<template #label="{ item }">
{{ item.name }}({{ 'id' in item ? item.id : '' }}) </template
><template #loading>查询人员中</template> </AsamMention
><output>{{ value }}</output>
<p class="example-paragraph">
此处用本地定时结果模拟应用请求;options/loading由宿主管理,旧请求结果由序号丢弃。映射选项字段时关闭内置过滤,使用服务端已过滤结果。
</p>
</div>
</template>
<script lang="ts" setup>
defineOptions({ name: 'AsamMentionLoadingExample' });
import { ref } from 'vue';
import { AsamMention } from '@asam-ui/ui';
const value = ref('');
const options = ref<{ id: string; name: string; inactive?: boolean }[]>([]);
const loading = ref(false);
let request = 0;
async function search(pattern: string) {
const current = ++request;
loading.value = true;
await new Promise((resolve) => setTimeout(resolve, 400));
if (current !== request) return;
options.value = [
{ id: pattern || 'alice', name: 'Alice ' + pattern },
{ id: 'disabled', name: '不可选', inactive: true }
];
loading.value = false;
}
</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">
<AsamMention
v-model="value"
:options="options"
:props="{ value: 'id', label: 'name', disabled: 'inactive' }"
:loading="loading"
:filter-option="false"
aria-label="异步人员"
@search="search"
>
<template #label="{ item }">
{{ item.name }}({{ 'id' in item ? item.id : '' }}) </template
><template #loading>查询人员中</template> </AsamMention
><output>{{ value }}</output>
<p class="example-paragraph">
此处用本地定时结果模拟应用请求;options/loading由宿主管理,旧请求结果由序号丢弃。映射选项字段时关闭内置过滤,使用服务端已过滤结果。
</p>
</div>
</template>
<script setup>
defineOptions({ name: 'AsamMentionLoadingExample' });
import { ref } from 'vue';
import { AsamMention } from '@asam-ui/ui';
const value = ref('');
const options = ref([]);
const loading = ref(false);
let request = 0;
async function search(pattern) {
const current = ++request;
loading.value = true;
await new Promise((resolve) => setTimeout(resolve, 400));
if (current !== request) return;
options.value = [
{ id: pattern || 'alice', name: 'Alice ' + pattern },
{ id: 'disabled', name: '不可选', inactive: true }
];
loading.value = false;
}
</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>
组合输入与 input 事件 ​
input 的 payload 为字符串;compositionstart/update/end 为原生 CompositionEvent,由实际 input/textarea 传入。组合输入阶段不应提前提交尚未完成的内容。此处示例可用于目标操作系统输入法验证。
组合输入与完整事件负载
<template>
<div class="example">
<AsamMention
v-model="value"
:options="options"
aria-label="组合输入提及"
@input="input = $event"
@compositionstart="record"
@compositionupdate="record"
@compositionend="record"
/><output>input 字符串:{{ input }};composition:{{ composition }}</output>
<p class="example-paragraph">
使用操作系统输入法编辑文本;组合期间不会将尚未提交的文本提前作为完整input模型。composition事件参数为原生CompositionEvent。
</p>
</div>
</template>
<script lang="ts" setup>
defineOptions({ name: 'AsamMentionCompositionExample' });
import { ref } from 'vue';
import { AsamMention } from '@asam-ui/ui';
const value = ref('');
const input = ref('');
const composition = ref('');
const options = [{ value: 'alice', label: 'Alice' }];
function record(event: CompositionEvent) {
composition.value = event.type + ': ' + event.data;
}
</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">
<AsamMention
v-model="value"
:options="options"
aria-label="组合输入提及"
@input="input = $event"
@compositionstart="record"
@compositionupdate="record"
@compositionend="record"
/><output>input 字符串:{{ input }};composition:{{ composition }}</output>
<p class="example-paragraph">
使用操作系统输入法编辑文本;组合期间不会将尚未提交的文本提前作为完整input模型。composition事件参数为原生CompositionEvent。
</p>
</div>
</template>
<script setup>
defineOptions({ name: 'AsamMentionCompositionExample' });
import { ref } from 'vue';
import { AsamMention } from '@asam-ui/ui';
const value = ref('');
const input = ref('');
const composition = ref('');
const options = [{ value: 'alice', label: 'Alice' }];
function record(event) {
composition.value = event.type + ': ' + event.data;
}
</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">
<AsamMention
v-model="value"
:options="options"
clearable
aria-label="继承输入事件"
@update:model-value="record('update', $event)"
@input="record('input', $event)"
@change="changed"
@clear="cleared"
@keydown="keyed"
@mouseenter="entered"
@mouseleave="left"
@focus="record('focus', $event.type)"
@blur="record('blur', $event.type)"
@compositionstart="record('compositionstart', $event.type)"
@compositionupdate="record('compositionupdate', $event.type)"
@compositionend="record('compositionend', $event.type)"
/>
<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, AsamMention } from '@asam-ui/ui';
import type { AsamMentionEmits } from '@asam-ui/ui';
defineOptions({ name: 'AsamMentionEventsExample' });
const value = ref('');
const options = [{ value: 'sam', label: 'Sam' }];
const events = ref<{ name: string; value: unknown }[]>([]);
function record(name: string, value: unknown) {
events.value.push({ name, value });
}
function changed(...[value, event]: AsamMentionEmits['change']) {
record('change', { value, event: event?.type });
}
function cleared(...[event]: AsamMentionEmits['clear']) {
record('clear', { event: event?.type });
}
function keyed(...[event]: AsamMentionEmits['keydown']) {
record('keydown', {
event: event.type,
key: event instanceof KeyboardEvent ? event.key : null
});
}
function entered(...[event]: AsamMentionEmits['mouseenter']) {
record('mouseenter', event.type);
}
function left(...[event]: AsamMentionEmits['mouseleave']) {
record('mouseleave', event.type);
}
</script>
<style scoped>
.example {
display: grid;
gap: var(--asam-space-md);
}
</style>
<template>
<div class="example">
<AsamMention
v-model="value"
:options="options"
clearable
aria-label="继承输入事件"
@update:model-value="record('update', $event)"
@input="record('input', $event)"
@change="changed"
@clear="cleared"
@keydown="keyed"
@mouseenter="entered"
@mouseleave="left"
@focus="record('focus', $event.type)"
@blur="record('blur', $event.type)"
@compositionstart="record('compositionstart', $event.type)"
@compositionupdate="record('compositionupdate', $event.type)"
@compositionend="record('compositionend', $event.type)"
/>
<AsamButton type="default" native-type="button">移出输入焦点</AsamButton>
<output>{{ JSON.stringify({ value, events }) }}</output>
</div>
</template>
<script setup>
import { ref } from 'vue';
import { AsamButton, AsamMention } from '@asam-ui/ui';
defineOptions({ name: 'AsamMentionEventsExample' });
const value = ref('');
const options = [{ value: 'sam', label: 'Sam' }];
const events = ref([]);
function record(name, value) {
events.value.push({ name, value });
}
function changed(...[value, event]) {
record('change', { value, event: event?.type });
}
function cleared(...[event]) {
record('clear', { event: event?.type });
}
function keyed(...[event]) {
record('keydown', {
event: event.type,
key: event instanceof KeyboardEvent ? event.key : null
});
}
function entered(...[event]) {
record('mouseenter', event.type);
}
function left(...[event]) {
record('mouseleave', event.type);
}
</script>
<style scoped>
.example {
display: grid;
gap: var(--asam-space-md);
}
</style>
readonly 与 disabled 原样传给原生。候选选择、clear、whole-remove 及继承输入事件不由 ASAM 再次过滤,公开实例行为以原生结果为准。
表单与整项删除 ​
提及的表单语义承接输入框:disabled 继承、validateEvent 控制 change/blur 校验。whole 整项删除可以通过 checkIsWhole 缩小允许删除的 token。prefix 多触发字符各为单字符,split 为单字符。
提及与表单校验
<template>
<div class="example">
<AsamBaseForm :model="model" :rules="rules" size="big">
<AsamFormItem label="消息" prop="message">
<AsamMention
v-model="model.message"
:options="options"
:check-is-whole="checkIsWhole"
whole
:prefix="['@', '#']"
/>
</AsamFormItem>
</AsamBaseForm>
<p class="example-paragraph">
失焦触发必填校验;默认按选项label过滤。整项删除只允许alice,试输 @alice 或 #alice
后选择并退格。
</p>
</div>
</template>
<script lang="ts" setup>
defineOptions({ name: 'AsamMentionFormExample' });
import { ref } from 'vue';
import { AsamMention, AsamBaseForm, AsamFormItem } from '@asam-ui/ui';
const model = ref({ message: '' });
const options = [
{ value: 'alice', label: 'Alice' },
{ value: 'bob', label: 'Bob' }
];
const rules = { message: [{ required: true, message: '请输入消息', trigger: 'blur' }] };
const checkIsWhole = (pattern: string) => pattern === 'alice';
</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">
<AsamBaseForm :model="model" :rules="rules" size="big">
<AsamFormItem label="消息" prop="message">
<AsamMention
v-model="model.message"
:options="options"
:check-is-whole="checkIsWhole"
whole
:prefix="['@', '#']"
/>
</AsamFormItem>
</AsamBaseForm>
<p class="example-paragraph">
失焦触发必填校验;默认按选项label过滤。整项删除只允许alice,试输 @alice 或 #alice
后选择并退格。
</p>
</div>
</template>
<script setup>
defineOptions({ name: 'AsamMentionFormExample' });
import { ref } from 'vue';
import { AsamMention, AsamBaseForm, AsamFormItem } from '@asam-ui/ui';
const model = ref({ message: '' });
const options = [
{ value: 'alice', label: 'Alice' },
{ value: 'bob', label: 'Bob' }
];
const rules = { message: [{ required: true, message: '请输入消息', trigger: 'blur' }] };
const checkIsWhole = (pattern) => pattern === 'alice';
</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>
API 阅读方式 ​
下方 API 来自当前公开类型与运行默认值。默认值标为“未知 / 未声明”时,不代表 false、空值或未支持。省略 size 保留祖先上下文继承。省略 disabled 保留表单禁用继承;validateEvent 控制校验事件,不用 disabled 代替。
完整继承输入组合 ​
min/max/step、formatter/parser、modelModifiers 与 textarea 参数原样交给 底层输入。 完整说明。
完整继承输入组合
<template>
<div class="example">
<AsamMention
v-model="numeric"
:options="options"
type="number"
:min="1"
:max="9"
:step="0.5"
aria-label="原生约束"
/>
<AsamMention
v-model="amount"
:options="options"
:formatter="formatter"
:parser="parser"
aria-label="继承格式化"
/>
<AsamMention
v-model.trim.lazy="modified"
:options="options"
aria-label="提及或建议修饰符"
@update:model-value="record"
/>
<AsamButton type="default" native-type="button" @click="modified = '42'"
>外部设置字符串 42</AsamButton
>
<AsamMention
v-model="text"
:options="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
改变显示并解析模型;模型使用字符串,修饰符处理委托原生;textarea
与字素计数适用于本入口的提及或建议。
</p>
</div>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import { AsamButton, AsamMention } from '@asam-ui/ui';
import type { AsamMentionEmits } from '@asam-ui/ui';
defineOptions({ name: 'AsamMentionNativeInputExample' });
const options = [{ value: 'Alice', label: 'Alice' }];
const numeric = ref<string>('1');
const amount = ref<string>('1234');
const modified = ref<string>('');
const text = ref('👩👩👧👦');
const updates = ref<(string | number)[]>([]);
function record(...[value]: AsamMentionEmits['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">
<AsamMention
v-model="numeric"
:options="options"
type="number"
:min="1"
:max="9"
:step="0.5"
aria-label="原生约束"
/>
<AsamMention
v-model="amount"
:options="options"
:formatter="formatter"
:parser="parser"
aria-label="继承格式化"
/>
<AsamMention
v-model.trim.lazy="modified"
:options="options"
aria-label="提及或建议修饰符"
@update:model-value="record"
/>
<AsamButton type="default" native-type="button" @click="modified = '42'"
>外部设置字符串 42</AsamButton
>
<AsamMention
v-model="text"
:options="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
改变显示并解析模型;模型使用字符串,修饰符处理委托原生;textarea
与字素计数适用于本入口的提及或建议。
</p>
</div>
</template>
<script setup>
import { ref } from 'vue';
import { AsamButton, AsamMention } from '@asam-ui/ui';
defineOptions({ name: 'AsamMentionNativeInputExample' });
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 示例同时实例化单行与多行 Mention。单行实际展示 prefix、suffix、prepend、append、password-icon 五槽,点击密码图标观察 visible 状态;这些输入装饰槽不由 textarea 模式渲染。
通过公开 mention.input 调用 focus、blur、select、clear;多行回填后调用 resizeTextarea 重新测量。 完整说明。
单行装饰槽与嵌套输入实例
<template>
<div class="example">
<div class="row">
<AsamButton type="default" @click="single?.input?.focus()">单行聚焦</AsamButton>
<AsamButton type="default" @click="single?.input?.blur()">单行失焦</AsamButton>
<AsamButton type="default" @click="single?.input?.select()">单行全选</AsamButton>
<AsamButton type="default" @click="single?.input?.clear()">单行清空</AsamButton>
</div>
<AsamMention
ref="single"
v-model="singleValue"
:options="options"
show-password
aria-label="单行提及实例"
>
<template #prefix>
<span>前</span>
</template>
<template #suffix>
<span>后</span>
</template>
<template #prepend>
<span>账号</span>
</template>
<template #append>
<span>域</span>
</template>
<template #password-icon="{ visible }">
<span :aria-label="visible ? '隐藏密码' : '显示密码'">
{{ visible ? '隐' : '显' }}
</span>
</template>
</AsamMention>
<div class="row">
<AsamButton type="default" @click="multi?.input?.focus()">多行聚焦</AsamButton>
<AsamButton type="default" @click="multi?.input?.blur()">多行失焦</AsamButton>
<AsamButton type="default" @click="multi?.input?.select()">多行全选</AsamButton>
<AsamButton type="default" @click="multi?.input?.clear()">多行清空</AsamButton>
<AsamButton type="default" @click="refillAndMeasure">回填并重新测量</AsamButton>
</div>
<AsamMention
ref="multi"
v-model="multiValue"
:options="options"
type="textarea"
:autosize="{ minRows: 2, maxRows: 4 }"
aria-label="多行提及实例"
/>
<output>{{
JSON.stringify({
singleValue,
multiValue,
singleHasInput: Boolean(single?.input?.input),
multiHasTextarea: Boolean(multi?.input?.textarea),
singleRef: single?.input?.ref?.tagName,
multiRef: multi?.input?.ref?.tagName,
passwordVisible: single?.input?.passwordVisible,
isComposing: single?.input?.isComposing,
autosize: multi?.input?.autosize,
textareaStyle: multi?.input?.textareaStyle
})
}}</output>
</div>
</template>
<script lang="ts" setup>
import { nextTick, ref } from 'vue';
import { AsamMention, AsamButton } from '@asam-ui/ui';
import type { AsamMentionExpose } from '@asam-ui/ui';
defineOptions({ name: 'AsamMentionInputInstanceExample' });
const single = ref<AsamMentionExpose>();
const multi = ref<AsamMentionExpose>();
const singleValue = ref<string>('seed');
const multiValue = ref<string>('first\nsecond');
const options = [{ value: 'sam', label: 'Sam' }];
async function refillAndMeasure() {
multiValue.value = 'first\nsecond\nthird\nfourth';
await nextTick();
multi.value?.input?.resizeTextarea();
}
</script>
<style scoped>
.example {
display: grid;
gap: var(--asam-space-md);
min-width: 0;
}
.row {
display: flex;
flex-wrap: wrap;
gap: var(--asam-space-sm);
}
output {
overflow-wrap: anywhere;
}
</style>
<template>
<div class="example">
<div class="row">
<AsamButton type="default" @click="single?.input?.focus()">单行聚焦</AsamButton>
<AsamButton type="default" @click="single?.input?.blur()">单行失焦</AsamButton>
<AsamButton type="default" @click="single?.input?.select()">单行全选</AsamButton>
<AsamButton type="default" @click="single?.input?.clear()">单行清空</AsamButton>
</div>
<AsamMention
ref="single"
v-model="singleValue"
:options="options"
show-password
aria-label="单行提及实例"
>
<template #prefix>
<span>前</span>
</template>
<template #suffix>
<span>后</span>
</template>
<template #prepend>
<span>账号</span>
</template>
<template #append>
<span>域</span>
</template>
<template #password-icon="{ visible }">
<span :aria-label="visible ? '隐藏密码' : '显示密码'">
{{ visible ? '隐' : '显' }}
</span>
</template>
</AsamMention>
<div class="row">
<AsamButton type="default" @click="multi?.input?.focus()">多行聚焦</AsamButton>
<AsamButton type="default" @click="multi?.input?.blur()">多行失焦</AsamButton>
<AsamButton type="default" @click="multi?.input?.select()">多行全选</AsamButton>
<AsamButton type="default" @click="multi?.input?.clear()">多行清空</AsamButton>
<AsamButton type="default" @click="refillAndMeasure">回填并重新测量</AsamButton>
</div>
<AsamMention
ref="multi"
v-model="multiValue"
:options="options"
type="textarea"
:autosize="{ minRows: 2, maxRows: 4 }"
aria-label="多行提及实例"
/>
<output>{{
JSON.stringify({
singleValue,
multiValue,
singleHasInput: Boolean(single?.input?.input),
multiHasTextarea: Boolean(multi?.input?.textarea),
singleRef: single?.input?.ref?.tagName,
multiRef: multi?.input?.ref?.tagName,
passwordVisible: single?.input?.passwordVisible,
isComposing: single?.input?.isComposing,
autosize: multi?.input?.autosize,
textareaStyle: multi?.input?.textareaStyle
})
}}</output>
</div>
</template>
<script setup>
import { nextTick, ref } from 'vue';
import { AsamMention, AsamButton } from '@asam-ui/ui';
defineOptions({ name: 'AsamMentionInputInstanceExample' });
const single = ref();
const multi = ref();
const singleValue = ref('seed');
const multiValue = ref('first\nsecond');
const options = [{ value: 'sam', label: 'Sam' }];
async function refillAndMeasure() {
multiValue.value = 'first\nsecond\nthird\nfourth';
await nextTick();
multi.value?.input?.resizeTextarea();
}
</script>
<style scoped>
.example {
display: grid;
gap: var(--asam-space-md);
min-width: 0;
}
.row {
display: flex;
flex-wrap: wrap;
gap: var(--asam-space-sm);
}
output {
overflow-wrap: anywhere;
}
</style>
动态原生类型与状态保留 ​
切换 text、password 与 number 时观察原生模型、焦点和前缀插槽。number 的文本选区限制、未提交 lazy 值与 textarea DOM 切换遵循原生实现,本入口不改写 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: 'AsamMentionDynamicTypeExample' },
__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.AsamMention), {
modelValue: value.value,
"onUpdate:modelValue": _cache[1] || (_cache[1] = ($event?: any) => ((value).value = $event)),
type: type.value,
min: 2,
max: 10,
step: 2,
options: suggestions,
"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-00e0f4cc";
},
"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-00e0f4cc] {
display: grid;
gap: var(--asam-space-md);
}
.actions[data-v-00e0f4cc] {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--asam-space-sm);
}
output[data-v-00e0f4cc] {
overflow-wrap: anywhere;
}
p[data-v-00e0f4cc]: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: 'AsamMentionDynamicTypeExample' }, {
__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.AsamMention), {
modelValue: value.value,
"onUpdate:modelValue": _cache[1] || (_cache[1] = $event => ((value).value = $event)),
type: type.value,
min: 2,
max: 10,
step: 2,
options: suggestions,
"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-54a2e827";
},
"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-54a2e827] {
display: grid;
gap: var(--asam-space-md);
}
.actions[data-v-54a2e827] {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--asam-space-sm);
}
output[data-v-54a2e827] {
overflow-wrap: anywhere;
}
p[data-v-54a2e827]: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>
<AsamMention
v-model="asam"
:disabled="disabled"
:readonly="readonly"
:validate-event="validateEvent"
:options="suggestions"
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, AsamMention } from '@asam-ui/ui';
defineOptions({ name: 'AsamMentionNativeDelegationExample' });
const asam = ref<string>('');
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>
<AsamMention
v-model="asam"
:disabled="disabled"
:readonly="readonly"
:validate-event="validateEvent"
:options="suggestions"
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, AsamMention } from '@asam-ui/ui';
defineOptions({ name: 'AsamMentionNativeDelegationExample' });
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>
API
属性 AsamMentionProps
| 属性名 | 说明 | 类型 | 默认值 |
|---|---|---|---|
id | 等价于原生 input id 属性 | string | undefined | — |
min | 原生输入边界与步长,包括继承的数字输入模式。 | (string | number) | undefined | — |
max | — | (string | number) | undefined | — |
step | — | (string | number) | undefined | — |
size | 显式控件密度;省略时继承按钮组、表单和配置提供器。 | enum"large" | "big" | "default" | "small"完整类型:AsamControlSize | undefined | — |
disabled | 是否禁用 | boolean | undefined | false |
modelModifiers | v-model 修饰符,参考 Vue 修饰符 | (AsamMentionProps<T>)["modelModifiers"] | — |
maxlength | 等价于原生 maxlength 属性 | string | number | undefined | — |
minlength | 等价于原生 minlength 属性 | string | number | undefined | — |
type | 输入类型,更多信息请参见 MDN | enum"number" | "text" | "email" | "search" | "tel" | "url" | "textarea" | "password"完整类型:(AsamMentionProps<T>)["type"] | — |
resize | 控制是否能被用户缩放 | enum"horizontal" | "vertical" | "none" | "both"完整类型:"horizontal" | "vertical" | "none" | "both" | undefined | — |
autosize | 文本域是否具有自适应高度。 | (AsamMentionProps<T>)["autosize"] | false |
autocomplete | 原生输入自动完成;联合类型包含大量字面量时可能触发 TS2590,详见 Vue 问题 10514。 | string | undefined | — |
formatter | 格式化显示内容。 | ((value: string) => string) | undefined | — |
parser | 解析显示内容。 | ((value: string) => string) | undefined | — |
placeholder | 输入框占位文本 | string | undefined | — |
form | 原生输入的表单关联。 | string | undefined | — |
readonly | 原生输入的只读状态。 | boolean | undefined | false |
clearable | 是否显示清除按钮 | boolean | undefined | false |
clearIcon | 自定义清除图标 | (AsamMentionProps<T>)["clearIcon"] | — |
showPassword | 可切换显示状态的密码输入。 | boolean | undefined | false |
showWordLimit | 字符计数。 | boolean | undefined | false |
wordLimitPosition | 字数统计的位置,仅当 show-word-limit 为 true 时生效。 | enum"outside" | "inside"完整类型:"outside" | "inside" | undefined | — |
suffixIcon | 后缀图标。 | (AsamMentionProps<T>)["suffixIcon"] | — |
prefixIcon | 前缀图标。 | (AsamMentionProps<T>)["prefixIcon"] | — |
containerRole | 容器角色;原生内部属性用于选择器组件。 | string | undefined | — |
tabindex | 等价于原生 tabindex 属性 | string | number | undefined | — |
validateEvent | 是否触发表单验证 | boolean | undefined | false |
inputStyle | 输入框或文本域元素样式。 | import("vue").StyleValue | false |
autofocus | 原生输入自动聚焦。 | boolean | undefined | false |
rows | 输入框行数,仅 type 为 'textarea' 时有效 | number | undefined | — |
ariaLabel | 原生 aria-label属性 | string | undefined | — |
inputmode | 原生虚拟键盘输入模式。 | enum"text" | "email" | "search" | "tel" | "url" | "none" | "numeric" | "decimal"完整类型:"text" | "email" | "search" | "tel" | "url" | "none" | "numeric" | "decimal" | undefined | — |
name | 原生属性 | string | undefined | — |
countGraphemes | 按字素统计输入长度;设置后不使用原生 maxlength 和 minlength。 | ((value: string) => number) | undefined | — |
options | 提及选项列表 | T[] | undefined | — |
prefix | 触发字段的前缀。字符串长度必须且只能为 1 | string | string[] | undefined | — |
split | 用于拆分提及的字符。字符串长度必须且只能为 1 | string | undefined | — |
filterOption | 定制筛选器选项逻辑 | false | ((pattern: string, option: T) => boolean) | undefined | false |
placement | 设置弹出位置 | enum"top" | "bottom"完整类型:"top" | "bottom" | undefined | — |
showArrow | 下拉菜单的内容是否有箭头 | boolean | undefined | false |
offset | 下拉面板偏移量 | number | undefined | — |
whole | 当退格键被按下做删除操作时,是否将提及部分作为整体删除 | boolean | undefined | false |
checkIsWhole | 当退格键被按下做删除操作时,检查是否将提及部分作为整体删除 | ((pattern: string, prefix: string) => boolean) | undefined | — |
modelValue | 输入值 | string | undefined | — |
loading | 自定义 loading内容 | boolean | undefined | false |
popperClass | 自定义浮层类名 | AsamMentionProps<T>["popperClass"] | false |
popperStyle | 自定义浮层类名 | import("vue").StyleValue | false |
popperOptions | popper.js 参数 | (AsamMentionProps<T>)["popperOptions"] | — |
props | options 的配置 | (AsamMentionProps<T>)["props"] | — |
事件 AsamMentionEmits
| 属性名 | 说明 | 类型 | 默认值 |
|---|---|---|---|
update:modelValue | — | [value: string | number] | — |
input | — | [value: string] | — |
change | 继承原生输入 change;原事件参数可省略。 | [value: string, event?: Event | undefined] | — |
clear | — | [event?: MouseEvent | undefined] | — |
mouseenter | — | [event: MouseEvent] | — |
mouseleave | — | [event: MouseEvent] | — |
keydown | 浏览器自动填充可能产生 Event,而非 KeyboardEvent。 | [event: Event | KeyboardEvent] | — |
compositionstart | 内部输入框或文本域的原生输入法组合事件。 | [event: CompositionEvent] | — |
compositionupdate | — | [event: CompositionEvent] | — |
compositionend | — | [event: CompositionEvent] | — |
search | — | [pattern: string, prefix: string] | — |
select | — | [option: T, prefix: string] | — |
whole-remove | — | [pattern: string, prefix: string] | — |
focus | — | [event: FocusEvent] | — |
blur | — | [event: FocusEvent] | — |
插槽 AsamMentionSlots
| 属性名 | 说明 | 类型 | 默认值 |
|---|---|---|---|
prefix | — | (() => unknown) | undefined | — |
suffix | — | (() => unknown) | undefined | — |
prepend | — | (() => unknown) | undefined | — |
append | — | (() => unknown) | undefined | — |
password-icon | — | ((props: { visible: boolean; }) => unknown) | undefined | — |
header | — | (() => unknown) | undefined | — |
footer | — | (() => unknown) | undefined | — |
loading | — | (() => unknown) | undefined | — |
label | — | ((props: { item: T; index: number; }) => unknown) | undefined | — |
实例方法与状态 AsamMentionExpose
| 属性名 | 说明 | 类型 | 默认值 |
|---|---|---|---|
input | — | (AsamMentionExpose)["input"] | — |
tooltip | — | (AsamMentionExpose)["tooltip"] | — |
dropdownVisible | — | boolean | — |
用法与契约补充说明 ​
使用场景 ​
用于评论、消息中的 @人员、#主题等提及,模型保存完整输入内容。modelValue 对齐原生 MentionProps 的字符串模型;update:modelValue 保留 string | number,Vue 的 number 修饰符可能让监听器收到数字。options 描述 value、label、disabled 等信息;扩展字段通过泛型保留。
完整继承输入组合 ​
min/max/step、formatter/parser、modelModifiers 与 textarea 参数原样交给 底层输入。trim/number/lazy 的实际更新和整项删除由原生处理;ASAM 不转换 modelValue、不保存独立草稿、不安排失焦后备提交,也不自行调度 change/blur 表单校验。直接 v-model.number 将数字写回字符串 prop 时,可能出现与原生相同的类型警告。建议保留文本模型,在应用或高级数据层处理业务数值;更新事件不能因此静默丢弃数字。旧 string | number 的 prop 用法迁移为字符串,数字输入 type=number 也使用文本模型。
实际单行装饰槽与嵌套输入实例 ​
通过公开 mention.input 调用 focus、blur、select、clear;多行回填后调用 resizeTextarea 重新测量。输出实际 input/textarea/ref、textareaStyle、autosize、passwordVisible 和 isComposing 状态,展示本入口的嵌套 InputInstance 路由。tooltip 与 dropdownVisible 继续按本页公开类型及现有多行/事件示例使用。
原生委托与事件记录 ​
下方完整 TS/JS 示例记录模型及事件顺序,并可切换禁用、只读和自动校验状态。省略的基础参数使用原生 defaults;显式 undefined/null/false 原样传入,合法值范围见 API。四档 size 是 ASAM 的视觉桥接;Password 额外固定 type=password,并在省略 showPassword 时启用显隐入口。
更多参数与事件说明 ​
完整继承输入事件 ​
除提及自己的 search、select、whole-remove,所有输入事件均由实际 input/textarea 承接:update:modelValue 为 string | number;input 为字符串;change 为字符串及可选原生 Event; clear 为可选 MouseEvent;focus/blur 为 FocusEvent;mouseenter/mouseleave 为 MouseEvent;keydown 为 KeyboardEvent 或浏览器自动填充触发的 Event; compositionstart/update/end 为 CompositionEvent。显式公开的监听器逐项转发, 每次原生触发只通知一次,不同时在外层 DOM 再挂同名监听器。
关联组件
参数与事件补充说明
参数与事件说明
id
必填:否;声明来源:ASAM 声明。
默认值与来源
未知 / 未声明固定上游源码默认表达式:undefined(2.14.7;源码事实,未作为 ASAM 运行实测)
min
必填:否;声明来源:ASAM 声明。
max
必填:否;声明来源:ASAM 声明。
step
必填:否;声明来源: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<(AsamMentionProps<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<(AsamMentionProps<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<(AsamMentionProps<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 运行实测)
options
必填:否;声明来源:ASAM 声明。
默认值与来源
未知 / 未声明固定上游文档默认:`[]`(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码工厂(未执行):() => [](2.14.7;源码事实,未作为 ASAM 运行实测)
prefix
必填:否;声明来源:ASAM 声明。
默认值与来源
未知 / 未声明固定上游文档默认:`'@'`(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:'@'(2.14.7;源码事实,未作为 ASAM 运行实测)
split
必填:否;声明来源:ASAM 声明。
默认值与来源
未知 / 未声明固定上游文档默认:`' '`(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:' '(2.14.7;源码事实,未作为 ASAM 运行实测)
filterOption
必填:否;声明来源:ASAM 声明。
filterOption 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false
事件参数:(pattern: string, option: T): boolean
默认值与来源
false(隐式 Boolean 默认;已安装组件)placement
必填:否;声明来源:ASAM 声明。
placement 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:"top" / "bottom"
默认值与来源
未知 / 未声明固定上游文档默认:`'bottom'`(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:'bottom'(2.14.7;源码事实,未作为 ASAM 运行实测)
showArrow
必填:否;声明来源:ASAM 声明。
showArrow 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
默认值与来源
false(隐式 Boolean 默认;已安装组件)固定上游文档默认:`false`(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
offset
必填:否;声明来源:ASAM 声明。
默认值与来源
未知 / 未声明固定上游文档默认:`0`(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:0(2.14.7;源码事实,未作为 ASAM 运行实测)
whole
必填:否;声明来源:ASAM 声明。
whole 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
默认值与来源
false(隐式 Boolean 默认;已安装组件)固定上游文档默认:`false`(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
checkIsWhole
必填:否;声明来源:ASAM 声明。
checkIsWhole 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(pattern: string, prefix: string): boolean
默认值与来源
未知 / 未声明固定上游文档默认:未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码未声明 default(2.14.7;源码事实,未作为 ASAM 运行实测)
modelValue
必填:否;声明来源:ASAM 声明。
默认值与来源
未知 / 未声明固定上游文档默认:未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
loading
必填:否;声明来源:ASAM 声明。
loading 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
默认值与来源
false(隐式 Boolean 默认;已安装组件)固定上游文档默认:`false`(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<(AsamMentionProps<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<(AsamMentionProps<T>)["popperOptions"]>, "modifiers">— 依赖声明popperOptions.strategy:PublicMember<NonNullable<(AsamMentionProps<T>)["popperOptions"]>, "strategy">— 依赖声明枚举:
"fixed"/"absolute"popperOptions.onFirstUpdate:PublicMember<NonNullable<(AsamMentionProps<T>)["popperOptions"]>, "onFirstUpdate">— 依赖声明事件参数:
(arg0: Parameters<Extract<NonNullable<PublicMember<NonNullable<(AsamMentionProps<T>)["popperOptions"]>, "onFirstUpdate">>, (...args: never[]) => unknown>>[0]): void
默认值与来源
未知 / 未声明固定上游文档默认:未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码工厂(未执行):() => ({}) as Partial<Options>(2.14.7;源码事实,未作为 ASAM 运行实测)
props
必填:否;声明来源:ASAM 声明。
props 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
props.value:string | undefined— 上游声明选项值的字段名;这是字段别名,不是选项本身的值。
固定上游文档默认:
未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)props.label:string | undefined— 上游声明选项标签的字段名;这是字段别名,不是选项本身的值。
固定上游文档默认:
未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)props.disabled:string | undefined— 上游声明选项禁用状态的字段名;这是字段别名,不是选项本身的值。
固定上游文档默认:
未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
默认值与来源
未知 / 未声明固定上游文档默认:`{value: 'value', label: 'label', disabled: 'disabled'}`(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码工厂(未执行):() => mentionDefaultProps(2.14.7;源码事实,未作为 ASAM 运行实测)
AsamMentionProps 公开类型视图
import type { Attrs } from 'vue';
import type { AsamMentionProps, AsamMentionOption, AsamControlSize } from '@asam-ui/ui';
type PublicMember<T, K extends PropertyKey> = T extends unknown ? K extends keyof T ? T[K] : never : never;
// AsamMentionProps
type PublicContract<T extends AsamMentionOption = AsamMentionOption> = {
readonly "id"?: string | undefined;
readonly "min"?: (string | number) | undefined;
readonly "max"?: (string | number) | undefined;
readonly "step"?: (string | number) | undefined;
readonly "size"?: AsamControlSize | undefined;
readonly "disabled"?: boolean | undefined;
readonly "modelModifiers"?: (AsamMentionProps<T>)["modelModifiers"];
readonly "maxlength"?: string | number | undefined;
readonly "minlength"?: string | number | undefined;
readonly "type"?: (AsamMentionProps<T>)["type"];
readonly "resize"?: "horizontal" | "vertical" | "none" | "both" | undefined;
readonly "autosize"?: (AsamMentionProps<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"?: (AsamMentionProps<T>)["clearIcon"];
readonly "showPassword"?: boolean | undefined;
readonly "showWordLimit"?: boolean | undefined;
readonly "wordLimitPosition"?: "outside" | "inside" | undefined;
readonly "suffixIcon"?: (AsamMentionProps<T>)["suffixIcon"];
readonly "prefixIcon"?: (AsamMentionProps<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 "options"?: T[] | undefined;
readonly "prefix"?: string | string[] | undefined;
readonly "split"?: string | undefined;
readonly "filterOption"?: false | ((pattern: string, option: T) => boolean) | undefined;
readonly "placement"?: "top" | "bottom" | undefined;
readonly "showArrow"?: boolean | undefined;
readonly "offset"?: number | undefined;
readonly "whole"?: boolean | undefined;
readonly "checkIsWhole"?: ((pattern: string, prefix: string) => boolean) | undefined;
readonly "modelValue"?: string | undefined;
readonly "loading"?: boolean | undefined;
readonly "popperClass"?: AsamMentionProps<T>["popperClass"];
readonly "popperStyle"?: import("vue").StyleValue;
readonly "popperOptions"?: (AsamMentionProps<T>)["popperOptions"];
readonly "props"?: (AsamMentionProps<T>)["props"];
};
参数与事件说明
update:modelValue
必填:是;声明来源:ASAM 声明。
input
必填:是;声明来源:ASAM 声明。
change
必填:是;声明来源:ASAM 声明。
clear
必填:是;声明来源:ASAM 声明。
mouseenter
必填:是;声明来源:ASAM 声明。
mouseleave
必填:是;声明来源:ASAM 声明。
keydown
必填:是;声明来源:ASAM 声明。
compositionstart
必填:是;声明来源:ASAM 声明。
compositionupdate
必填:是;声明来源:ASAM 声明。
compositionend
必填:是;声明来源:ASAM 声明。
search
必填:是;声明来源:ASAM 声明。
select
必填:是;声明来源:ASAM 声明。
whole-remove
必填:是;声明来源:ASAM 声明。
focus
必填:是;声明来源:ASAM 声明。
blur
必填:是;声明来源:ASAM 声明。
AsamMentionEmits 公开类型视图
import type { AsamMentionEmits, AsamMentionOption } from '@asam-ui/ui';
// AsamMentionEmits
type PublicContract<T extends AsamMentionOption = AsamMentionOption> = {
"update:modelValue": [value: string | number];
"input": [value: string];
"change": [value: string, event?: Event | undefined];
"clear": [event?: MouseEvent | undefined];
"mouseenter": [event: MouseEvent];
"mouseleave": [event: MouseEvent];
"keydown": [event: Event | KeyboardEvent];
"compositionstart": [event: CompositionEvent];
"compositionupdate": [event: CompositionEvent];
"compositionend": [event: CompositionEvent];
"search": [pattern: string, prefix: string];
"select": [option: T, prefix: string];
"whole-remove": [pattern: string, prefix: string];
"focus": [event: FocusEvent];
"blur": [event: FocusEvent];
};
参数与事件说明
prefix
必填:否;声明来源:ASAM 声明。
prefix 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(): unknown
suffix
必填:否;声明来源:ASAM 声明。
suffix 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(): unknown
prepend
必填:否;声明来源:ASAM 声明。
prepend 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(): unknown
append
必填:否;声明来源:ASAM 声明。
append 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(): unknown
password-icon
必填:否;声明来源:ASAM 声明。
password-icon 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(props: { visible: boolean; }): unknown
header
必填:否;声明来源:ASAM 声明。
header 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(): unknown
footer
必填:否;声明来源:ASAM 声明。
footer 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(): unknown
loading
必填:否;声明来源:ASAM 声明。
loading 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(): unknown
label
必填:否;声明来源:ASAM 声明。
label 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(props: { item: T; index: number; }): unknown
AsamMentionSlots 公开类型视图
import type { AsamMentionSlots, AsamMentionOption } from '@asam-ui/ui';
// AsamMentionSlots
type PublicContract<T extends AsamMentionOption = AsamMentionOption> = {
"prefix"?: (() => unknown) | undefined;
"suffix"?: (() => unknown) | undefined;
"prepend"?: (() => unknown) | undefined;
"append"?: (() => unknown) | undefined;
"password-icon"?: ((props: { visible: boolean; }) => unknown) | undefined;
"header"?: (() => unknown) | undefined;
"footer"?: (() => unknown) | undefined;
"loading"?: (() => unknown) | undefined;
"label"?: ((props: { item: T; index: number; }) => unknown) | undefined;
};
参数与事件说明
input
必填:是;声明来源:ASAM 声明。
tooltip
必填:是;声明来源:ASAM 声明。
dropdownVisible
必填:是;声明来源:ASAM 声明。
dropdownVisible 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
AsamMentionExpose 公开类型视图
import type { AsamMentionExpose } from '@asam-ui/ui';
// AsamMentionExpose
type PublicContract = {
readonly "input": (AsamMentionExpose)["input"];
readonly "tooltip": (AsamMentionExpose)["tooltip"];
readonly "dropdownVisible": boolean;
};