使用场景 ​
用于数量和有限精度的数值输入。v-model 为 number、null 或 undefined;change 同时提供新值与之前的值。需要格式化文本展示时见 Input。
范围与步进 ​
min/max 控制范围,step 控制步长;stepStrictly 约束为步长倍数。
省略 min/max 时保留固定原生的 Number.MIN_SAFE_INTEGER / Number.MAX_SAFE_INTEGER 默认边界,提交不安全整数会裁剪到该范围。应用需要其他范围时显式配置边界。
默认安全整数边界
<template>
<div class="example">
<AsamInputNumber v-model="value" aria-label="默认安全整数" />
<AsamButton type="default" native-type="button">移出焦点以提交</AsamButton>
<output>{{ JSON.stringify({ value }) }}</output>
<p class="example-paragraph">
省略 min/max 时边界为 -9007199254740991 到
9007199254740991;提交更大或更小的值会裁剪到边界。
</p>
</div>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import { AsamButton, AsamInputNumber } from '@asam-ui/ui';
defineOptions({ name: 'AsamInputNumberSafeIntegersExample' });
const value = ref<number | null | undefined>(1);
</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">
<AsamInputNumber v-model="value" aria-label="默认安全整数" />
<AsamButton type="default" native-type="button">移出焦点以提交</AsamButton>
<output>{{ JSON.stringify({ value }) }}</output>
<p class="example-paragraph">
省略 min/max 时边界为 -9007199254740991 到
9007199254740991;提交更大或更小的值会裁剪到边界。
</p>
</div>
</template>
<script setup>
import { ref } from 'vue';
import { AsamButton, AsamInputNumber } from '@asam-ui/ui';
defineOptions({ name: 'AsamInputNumberSafeIntegersExample' });
const value = ref(1);
</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">
<AsamInputNumber
v-model="value"
v-bind="{ class: 'field', 'aria-label': '采购数量' }"
:min="0"
:max="20"
:step="2"
step-strictly
@change="(next, previous) => (change = String(previous) + ' → ' + String(next))"
/>
<output>数量:{{ value }};变化:{{ change }}</output>
</div>
</template>
<script lang="ts" setup>
defineOptions({ name: 'AsamInputNumberBasicExample' });
import { ref } from 'vue';
import { AsamInputNumber } from '@asam-ui/ui';
const value = ref<number | null | undefined>(4);
const change = ref('尚未变化');
</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">
<AsamInputNumber
v-model="value"
v-bind="{ class: 'field', 'aria-label': '采购数量' }"
:min="0"
:max="20"
:step="2"
step-strictly
@change="(next, previous) => (change = String(previous) + ' → ' + String(next))"
/>
<output>数量:{{ value }};变化:{{ change }}</output>
</div>
</template>
<script setup>
defineOptions({ name: 'AsamInputNumberBasicExample' });
import { ref } from 'vue';
import { AsamInputNumber } from '@asam-ui/ui';
const value = ref(4);
const change = ref('尚未变化');
</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>
精度与清空值 ​
precision 控制小数位;步长小数位不要超过 precision。valueOnClear 明确清空后的值;disabledScientific 禁止科学计数法字符。
精度与清空值
<template>
<div class="example">
<AsamInputNumber
v-model="value"
v-bind="{ class: 'field', 'aria-label': '单价' }"
:precision="2"
:step="0.25"
:min="0"
:value-on-clear="0"
controls-position="right"
disabled-scientific
/>
<AsamInputNumber
v-model="plain"
v-bind="{ class: 'field', 'aria-label': '无控制按钮数字' }"
:controls="false"
align="left"
/>
<output>单价:{{ value }};普通数值:{{ plain }}</output>
</div>
</template>
<script lang="ts" setup>
defineOptions({ name: 'AsamInputNumberPrecisionExample' });
import { ref } from 'vue';
import { AsamInputNumber } from '@asam-ui/ui';
const value = ref<number | null | undefined>(12.5);
const plain = ref<number | null | undefined>(3);
</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">
<AsamInputNumber
v-model="value"
v-bind="{ class: 'field', 'aria-label': '单价' }"
:precision="2"
:step="0.25"
:min="0"
:value-on-clear="0"
controls-position="right"
disabled-scientific
/>
<AsamInputNumber
v-model="plain"
v-bind="{ class: 'field', 'aria-label': '无控制按钮数字' }"
:controls="false"
align="left"
/>
<output>单价:{{ value }};普通数值:{{ plain }}</output>
</div>
</template>
<script setup>
defineOptions({ name: 'AsamInputNumberPrecisionExample' });
import { ref } from 'vue';
import { AsamInputNumber } from '@asam-ui/ui';
const value = ref(12.5);
const plain = ref(3);
</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/suffix 显示单位;increase-icon/decrease-icon 定义步进图标。实例公开 focus 与 blur。
单位与控制图标
<!-- 此演示还使用 @asam-ui/icons-vue,请按官网对应指南配置这些公开依赖。 -->
<template>
<div class="example">
<AsamInputNumber
ref="input"
v-model="value"
v-bind="{ class: 'field', 'aria-label': '重量' }"
>
<template #prefix> 重量 </template>
<template #suffix> kg </template>
<template #increase-icon>
<Plus style="width: 16px" />
</template>
<template #decrease-icon>
<Minus style="width: 16px" />
</template>
</AsamInputNumber>
<div class="row">
<AsamButton type="default" @click="input?.focus()"> 聚焦数字 </AsamButton>
<AsamButton type="default" @click="input?.blur()"> 失焦数字 </AsamButton>
</div>
</div>
</template>
<script lang="ts" setup>
defineOptions({ name: 'AsamInputNumberIconsExample' });
import { ref } from 'vue';
import { AsamInputNumber, AsamButton } from '@asam-ui/ui';
import type { AsamInputNumberExpose } from '@asam-ui/ui';
import { Plus, Minus } from '@asam-ui/icons-vue';
const input = ref<AsamInputNumberExpose>();
const value = ref<number | null | undefined>(8);
</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">
<AsamInputNumber
ref="input"
v-model="value"
v-bind="{ class: 'field', 'aria-label': '重量' }"
>
<template #prefix> 重量 </template>
<template #suffix> kg </template>
<template #increase-icon>
<Plus style="width: 16px" />
</template>
<template #decrease-icon>
<Minus style="width: 16px" />
</template>
</AsamInputNumber>
<div class="row">
<AsamButton type="default" @click="input?.focus()"> 聚焦数字 </AsamButton>
<AsamButton type="default" @click="input?.blur()"> 失焦数字 </AsamButton>
</div>
</div>
</template>
<script setup>
defineOptions({ name: 'AsamInputNumberIconsExample' });
import { ref } from 'vue';
import { AsamInputNumber, AsamButton } from '@asam-ui/ui';
import { Plus, Minus } from '@asam-ui/icons-vue';
const input = ref();
const value = ref(8);
</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">
<AsamInputNumber
size="large"
v-bind="{ class: 'field', 'aria-label': 'large尺寸' }"
:model-value="8"
/>
<AsamInputNumber
size="big"
v-bind="{ class: 'field', 'aria-label': 'big尺寸' }"
:model-value="8"
/>
<AsamInputNumber
size="default"
v-bind="{ class: 'field', 'aria-label': 'default尺寸' }"
:model-value="8"
/>
<AsamInputNumber
size="small"
v-bind="{ class: 'field', 'aria-label': 'small尺寸' }"
:model-value="8"
/>
</div>
<AsamConfigProvider :size="density">
<div class="example">
<AsamInputNumber
v-bind="{ class: 'field', 'aria-label': '继承尺寸' }"
:model-value="8"
/>
<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: 'AsamInputNumberSizesExample' });
import { ref } from 'vue';
import { AsamInputNumber, 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">
<AsamInputNumber
size="large"
v-bind="{ class: 'field', 'aria-label': 'large尺寸' }"
:model-value="8"
/>
<AsamInputNumber
size="big"
v-bind="{ class: 'field', 'aria-label': 'big尺寸' }"
:model-value="8"
/>
<AsamInputNumber
size="default"
v-bind="{ class: 'field', 'aria-label': 'default尺寸' }"
:model-value="8"
/>
<AsamInputNumber
size="small"
v-bind="{ class: 'field', 'aria-label': 'small尺寸' }"
:model-value="8"
/>
</div>
<AsamConfigProvider :size="density">
<div class="example">
<AsamInputNumber
v-bind="{ class: 'field', 'aria-label': '继承尺寸' }"
:model-value="8"
/>
<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: 'AsamInputNumberSizesExample' });
import { ref } from 'vue';
import { AsamInputNumber, 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 扩展与迁移 ​
四档 size 保持继承;模型使用数字,空值按 valueOnClear 处理,不将字符串模型直接迁入。默认清空与非法格式可产生 null;input、update:modelValue 和 change 的新旧值均如实保留该空值。
数字格式化与解析 ​
formatter 改变显示,parser 解析编辑文本;模型和事件仍保留 number、null 或 undefined。动态切换 formatter 原样交给原生,ASAM 不通过 key 重建输入节点,不修复原生 text/number 切换的选区限制。tabindex 作用于实际 input。
格式化、解析与内部 tabindex
<template>
<div class="example">
<AsamInputNumber
v-model="amount"
:formatter="formatter"
:parser="parser"
:min="0"
:max="10000"
:tabindex="7"
aria-label="格式化金额"
/><output>数值模型:{{ amount }};类型:{{ typeof amount }}</output>
<p class="example-paragraph">
编辑 $2,345 后提交或失焦,模型为数字 2345。formatter 只改变显示;parser
移除装饰后再进行范围/精度校验。
</p>
</div>
</template>
<script lang="ts" setup>
defineOptions({ name: 'AsamInputNumberFormatExample' });
import { ref } from 'vue';
import { AsamInputNumber } from '@asam-ui/ui';
const amount = ref<number | null | undefined>(1234);
const formatter = (value: string | number) =>
value === '' ? '' : '$' + String(value).replace(/\B(?=(\d{3})+(?!\d))/g, ',');
const parser = (value: string) => value.replace(/[$,]/g, '');
</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">
<AsamInputNumber
v-model="amount"
:formatter="formatter"
:parser="parser"
:min="0"
:max="10000"
:tabindex="7"
aria-label="格式化金额"
/><output>数值模型:{{ amount }};类型:{{ typeof amount }}</output>
<p class="example-paragraph">
编辑 $2,345 后提交或失焦,模型为数字 2345。formatter 只改变显示;parser
移除装饰后再进行范围/精度校验。
</p>
</div>
</template>
<script setup>
defineOptions({ name: 'AsamInputNumberFormatExample' });
import { ref } from 'vue';
import { AsamInputNumber } from '@asam-ui/ui';
const amount = ref(1234);
const formatter = (value) =>
value === '' ? '' : '$' + String(value).replace(/\B(?=(\d{3})+(?!\d))/g, ',');
const parser = (value) => value.replace(/[$,]/g, '');
</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>
空值、非法格式与恢复 ​
省略 valueOnClear 时默认清空为 null,显式配置可使用数字、null、min 或 max。 完整说明。
空值、非法格式与恢复
<template>
<div class="example">
<AsamInputNumber
v-model="value"
aria-label="默认清空数字"
@input="record('input', [$event])"
@update:model-value="record('update', [$event])"
@change="recordChange"
/>
<AsamButton type="default" native-type="button" @click="value = 1">恢复为 1</AsamButton>
<AsamInputNumber
v-model="amount"
:formatter="formatter"
:parser="parser"
aria-label="非法格式金额"
@change="recordAmountChange"
/>
<AsamButton type="default" native-type="button">提交格式金额</AsamButton>
<output>{{ JSON.stringify({ value, amount, events }) }}</output>
<p class="example-paragraph">
清空默认产生 null;输入非法格式也可产生 null。重新输入数字会从空值恢复,change
保留新旧值。
</p>
</div>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import { AsamButton, AsamInputNumber } from '@asam-ui/ui';
import type { AsamInputNumberEmits } from '@asam-ui/ui';
defineOptions({ name: 'AsamInputNumberNullValuesExample' });
const value = ref<number | null | undefined>(1);
const amount = ref<number | null | undefined>(2);
const events = ref<{ name: string; args: (number | null | undefined)[] }[]>([]);
function record(name: string, args: (number | null | undefined)[]) {
events.value.push({ name, args });
}
function recordChange(...args: AsamInputNumberEmits['change']) {
record('change', args);
}
function recordAmountChange(...args: AsamInputNumberEmits['change']) {
record('amount-change', args);
}
const formatter = (value: string) => (value === '' ? '' : '$' + value);
const parser = (value: string) => value.replace(/[$,]/g, '');
</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">
<AsamInputNumber
v-model="value"
aria-label="默认清空数字"
@input="record('input', [$event])"
@update:model-value="record('update', [$event])"
@change="recordChange"
/>
<AsamButton type="default" native-type="button" @click="value = 1">恢复为 1</AsamButton>
<AsamInputNumber
v-model="amount"
:formatter="formatter"
:parser="parser"
aria-label="非法格式金额"
@change="recordAmountChange"
/>
<AsamButton type="default" native-type="button">提交格式金额</AsamButton>
<output>{{ JSON.stringify({ value, amount, events }) }}</output>
<p class="example-paragraph">
清空默认产生 null;输入非法格式也可产生 null。重新输入数字会从空值恢复,change
保留新旧值。
</p>
</div>
</template>
<script setup>
import { ref } from 'vue';
import { AsamButton, AsamInputNumber } from '@asam-ui/ui';
defineOptions({ name: 'AsamInputNumberNullValuesExample' });
const value = ref(1);
const amount = ref(2);
const events = ref([]);
function record(name, args) {
events.value.push({ name, args });
}
function recordChange(...args) {
record('change', args);
}
function recordAmountChange(...args) {
record('amount-change', args);
}
const formatter = (value) => (value === '' ? '' : '$' + value);
const parser = (value) => value.replace(/[$,]/g, '');
</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>
完整输入边界 ​
stepStrictly 保证步长倍数,precision 限定小数位且不能小于 step 的小数位数。 完整说明。
严格步进、精度和输入边界
<template>
<div class="example">
<div class="row">
<AsamCheckboxItem v-model="disabled">禁用</AsamCheckboxItem
><AsamCheckboxItem v-model="readonly">只读</AsamCheckboxItem
><AsamCheckboxItem v-model="controls">控制按钮</AsamCheckboxItem>
</div>
<AsamInputNumber
v-model="value"
:min="0"
:max="12"
:step="3"
step-strictly
:value-on-clear="0"
:disabled="disabled"
:readonly="readonly"
:controls="controls"
controls-position="right"
disabled-scientific
aria-label="严格倍数"
@change="(next, previous) => (message = String(previous) + ' → ' + String(next))"
/><AsamInputNumber
v-model="decimal"
:step="0.1"
:precision="2"
aria-label="两位小数"
/><output>{{ message }};精度值 {{ decimal }}</output>
<p class="example-paragraph">
范围外输入在提交时裁剪;清空后回到0;e/E科学记数输入被禁止。无效文本不会变成 NaN 模型。
</p>
</div>
</template>
<script lang="ts" setup>
defineOptions({ name: 'AsamInputNumberBoundariesExample' });
import { ref } from 'vue';
import { AsamCheckboxItem, AsamInputNumber } from '@asam-ui/ui';
const value = ref<number | null | undefined>(3);
const decimal = ref<number | null | undefined>(1.23);
const disabled = ref(false);
const readonly = ref(false);
const controls = ref(true);
const message = ref('');
</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">
<div class="row">
<AsamCheckboxItem v-model="disabled">禁用</AsamCheckboxItem
><AsamCheckboxItem v-model="readonly">只读</AsamCheckboxItem
><AsamCheckboxItem v-model="controls">控制按钮</AsamCheckboxItem>
</div>
<AsamInputNumber
v-model="value"
:min="0"
:max="12"
:step="3"
step-strictly
:value-on-clear="0"
:disabled="disabled"
:readonly="readonly"
:controls="controls"
controls-position="right"
disabled-scientific
aria-label="严格倍数"
@change="(next, previous) => (message = String(previous) + ' → ' + String(next))"
/><AsamInputNumber
v-model="decimal"
:step="0.1"
:precision="2"
aria-label="两位小数"
/><output>{{ message }};精度值 {{ decimal }}</output>
<p class="example-paragraph">
范围外输入在提交时裁剪;清空后回到0;e/E科学记数输入被禁止。无效文本不会变成 NaN 模型。
</p>
</div>
</template>
<script setup>
defineOptions({ name: 'AsamInputNumberBoundariesExample' });
import { ref } from 'vue';
import { AsamCheckboxItem, AsamInputNumber } from '@asam-ui/ui';
const value = ref(3);
const decimal = ref(1.23);
const disabled = ref(false);
const readonly = ref(false);
const controls = ref(true);
const message = ref('');
</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 代替。
动态表单状态与无障碍范围 ​
disabled、min/max 的更新委托 底层输入。 完整说明。
动态表单状态与无障碍范围
<template>
<!-- prettier-ignore -->
<div class="example">
<AsamCheckboxItem v-model="disabled">禁用表单</AsamCheckboxItem>
<AsamBaseForm
:model="{ value }"
:disabled="disabled"
>
<AsamInputNumber
v-model="value"
:min="min"
:max="max"
aria-label="动态数字范围"
/>
</AsamBaseForm>
<AsamButton type="default"
native-type="button"
@click="
min = 2;
max = 8;
"
>
范围 2–8
</AsamButton>
<AsamButton type="default"
native-type="button"
@click="
min = -Infinity;
max = Infinity;
"
>
显式无限范围
</AsamButton>
<output>{{
JSON.stringify({ value, disabled, min: String(min), max: String(max) })
}}</output>
</div>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import { AsamCheckboxItem, AsamButton, AsamBaseForm, AsamInputNumber } from '@asam-ui/ui';
defineOptions({ name: 'AsamInputNumberDynamicStateExample' });
const value = ref<number | null | undefined>(3);
const disabled = ref(true);
const min = ref(0);
const max = ref(10);
</script>
<style scoped>
.example {
display: grid;
gap: var(--asam-space-md);
}
</style>
<template>
<!-- prettier-ignore -->
<div class="example">
<AsamCheckboxItem v-model="disabled">禁用表单</AsamCheckboxItem>
<AsamBaseForm
:model="{ value }"
:disabled="disabled"
>
<AsamInputNumber
v-model="value"
:min="min"
:max="max"
aria-label="动态数字范围"
/>
</AsamBaseForm>
<AsamButton type="default"
native-type="button"
@click="
min = 2;
max = 8;
"
>
范围 2–8
</AsamButton>
<AsamButton type="default"
native-type="button"
@click="
min = -Infinity;
max = Infinity;
"
>
显式无限范围
</AsamButton>
<output>{{
JSON.stringify({ value, disabled, min: String(min), max: String(max) })
}}</output>
</div>
</template>
<script setup>
import { ref } from 'vue';
import { AsamCheckboxItem, AsamButton, AsamBaseForm, AsamInputNumber } from '@asam-ui/ui';
defineOptions({ name: 'AsamInputNumberDynamicStateExample' });
const value = ref(3);
const disabled = ref(true);
const min = ref(0);
const max = ref(10);
</script>
<style scoped>
.example {
display: grid;
gap: var(--asam-space-md);
}
</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>
<AsamInputNumber
v-model="asam"
:disabled="disabled"
:readonly="readonly"
:validate-event="validateEvent"
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, AsamInputNumber } from '@asam-ui/ui';
defineOptions({ name: 'AsamInputNumberNativeDelegationExample' });
const asam = ref<number | null | undefined>(1);
const disabled = ref(false);
const readonly = ref(false);
const validateEvent = ref(true);
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>
<AsamInputNumber
v-model="asam"
:disabled="disabled"
:readonly="readonly"
:validate-event="validateEvent"
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, AsamInputNumber } from '@asam-ui/ui';
defineOptions({ name: 'AsamInputNumberNativeDelegationExample' });
const asam = ref(1);
const disabled = ref(false);
const readonly = ref(false);
const validateEvent = ref(true);
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
属性 AsamInputNumberProps
| 属性名 | 说明 | 类型 | 默认值 |
|---|---|---|---|
id | 等价于原生 input id 属性 | string | undefined | — |
step | 计数器步长 | number | undefined | — |
stepStrictly | 是否只能输入 step 的倍数 | boolean | undefined | false |
max | 上界,默认 Number.MAX_SAFE_INTEGER。 | number | undefined | — |
min | 下界,默认 Number.MIN_SAFE_INTEGER。 | number | undefined | — |
modelValue | 输入值 | number | null | undefined | — |
readonly | 原生输入的只读状态。 | boolean | undefined | false |
disabled | 是否禁用 | boolean | undefined | false |
size | 显式控件密度;省略时继承按钮组、表单和配置提供器。 | enum"large" | "big" | "default" | "small"完整类型:AsamControlSize | undefined | — |
controls | 是否使用控制按钮 | boolean | undefined | false |
controlsPosition | 控制按钮位置 | enum"" | "right"完整类型:"" | "right" | undefined | — |
valueOnClear | 当输入框被清空时显示的值 | enum"max" | "min"完整类型:number | "max" | "min" | null | undefined | — |
name | 原生属性 | string | undefined | — |
placeholder | 输入框占位文本 | string | undefined | — |
precision | 数值精度 | number | undefined | — |
validateEvent | 是否触发表单验证 | boolean | undefined | false |
ariaLabel | 原生 aria-label属性 | string | undefined | — |
inputmode | 原生虚拟键盘输入模式。 | enum"text" | "email" | "search" | "tel" | "url" | "none" | "numeric" | "decimal"完整类型:"text" | "email" | "search" | "tel" | "url" | "none" | "numeric" | "decimal" | undefined | — |
align | 内部输入文本对齐 | enum"right" | "left" | "center"完整类型:"right" | "left" | "center" | undefined | — |
disabledScientific | 是否禁止输入科学计数法字符,例如 e、E。 | boolean | undefined | false |
formatter | 格式化显示文字,同时保留数字模型。 | ((value: string) => string) | undefined | — |
parser | 应用数字边界与精度前解析编辑后的显示文字。 | ((value: string) => string) | undefined | — |
tabindex | 实际内部输入框的键盘顺序,默认 0。 | string | number | undefined | — |
事件 AsamInputNumberEmits
| 属性名 | 说明 | 类型 | 默认值 |
|---|---|---|---|
update:modelValue | 空值或无效输入在提交前后都可能产生 null。 | [value: number | null | undefined] | — |
change | — | [value: number | null | undefined, previousValue: number | null | undefined] | — |
input | — | [value: number | null | undefined] | — |
focus | — | [event: FocusEvent] | — |
blur | — | [event: FocusEvent] | — |
插槽 AsamInputNumberSlots
| 属性名 | 说明 | 类型 | 默认值 |
|---|---|---|---|
prefix | — | (() => unknown) | undefined | — |
suffix | — | (() => unknown) | undefined | — |
increase-icon | — | (() => unknown) | undefined | — |
decrease-icon | — | (() => unknown) | undefined | — |
实例方法与状态 AsamInputNumberExpose
| 属性名 | 说明 | 类型 | 默认值 |
|---|---|---|---|
focus | — | () => void | — |
blur | — | () => void | — |
用法与契约补充说明 ​
空值、非法格式与恢复 ​
省略 valueOnClear 时默认清空为 null,显式配置可使用数字、null、min 或 max。 非法格式编辑可能产生 null;重新键入有效数字即可恢复。模型及 update:modelValue、 input、change 的新旧值类型均为 number | null | undefined,不能把 null 当作字符串 或从事件协议中删除。
完整输入边界 ​
stepStrictly 保证步长倍数,precision 限定小数位且不能小于 step 的小数位数。min/max 在提交时限定范围;valueOnClear 指定清空后的值。disabled、readonly、controls、controlsPosition 分别控制禁用、只读、按钮显示和按钮位置。disabledScientific 禁止键盘 e/E,业务仍应校验数据。
动态表单状态与无障碍范围 ​
disabled、min/max 的更新委托 底层输入。2.14.7 原生在挂载时初始化部分 ARIA 属性,后续动态更新可能仍显示旧的 aria-disabled/aria-valuemin/aria-valuemax。ASAM 保留这一兼容限制,不使用 MutationObserver 改写属性,也不以重挂载恢复选区。
原生委托与事件记录 ​
下方完整 TS/JS 示例记录模型及事件顺序,并可切换禁用、只读和自动校验状态。省略的基础参数使用原生 defaults;显式 undefined/null/false 原样传入,合法值范围见 API。四档 size 是 ASAM 的视觉桥接;Password 额外固定 type=password,并在省略 showPassword 时启用显隐入口。
关联组件
参数与事件补充说明
参数与事件说明
id
必填:否;声明来源:ASAM 声明。
默认值与来源
未知 / 未声明固定上游文档默认:未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:undefined(2.14.7;源码事实,未作为 ASAM 运行实测)
step
必填:否;声明来源:ASAM 声明。
默认值与来源
未知 / 未声明固定上游文档默认:1(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:1(2.14.7;源码事实,未作为 ASAM 运行实测)
stepStrictly
必填:否;声明来源:ASAM 声明。
stepStrictly 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
默认值与来源
false(隐式 Boolean 默认;已安装组件)固定上游文档默认:false(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
max
必填:否;声明来源:ASAM 声明。
默认值与来源
未知 / 未声明固定上游文档默认:Number.MAX_SAFE_INTEGER(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:Number.MAX_SAFE_INTEGER(2.14.7;源码事实,未作为 ASAM 运行实测)
min
必填:否;声明来源:ASAM 声明。
默认值与来源
未知 / 未声明固定上游文档默认:Number.MIN_SAFE_INTEGER(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:Number.MIN_SAFE_INTEGER(2.14.7;源码事实,未作为 ASAM 运行实测)
modelValue
必填:否;声明来源:ASAM 声明。
默认值与来源
未知 / 未声明固定上游文档默认:未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码未声明 default(2.14.7;源码事实,未作为 ASAM 运行实测)
readonly
必填:否;声明来源:ASAM 声明。
readonly 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
默认值与来源
false(隐式 Boolean 默认;已安装组件)固定上游文档默认:false(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
disabled
必填:否;声明来源:ASAM 声明。
disabled 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
默认值与来源
false(隐式 Boolean 默认;已安装组件)固定上游文档默认:false(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:undefined(2.14.7;源码事实,未作为 ASAM 运行实测)
size
必填:否;声明来源:ASAM 声明。
size 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:"large" / "big" / "default" / "small"
controls
必填:否;声明来源:ASAM 声明。
controls 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
默认值与来源
false(隐式 Boolean 默认;已安装组件)固定上游文档默认:true(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:true(2.14.7;源码事实,未作为 ASAM 运行实测)
controlsPosition
必填:否;声明来源:ASAM 声明。
controlsPosition 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:"" / "right"
默认值与来源
未知 / 未声明固定上游文档默认:未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:''(2.14.7;源码事实,未作为 ASAM 运行实测)
valueOnClear
必填:否;声明来源:ASAM 声明。
valueOnClear 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:"max" / "min"
默认值与来源
未知 / 未声明固定上游文档默认:未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:null(2.14.7;源码事实,未作为 ASAM 运行实测)
name
必填:否;声明来源:ASAM 声明。
默认值与来源
未知 / 未声明固定上游文档默认:未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
placeholder
必填:否;声明来源:ASAM 声明。
默认值与来源
未知 / 未声明固定上游文档默认:未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
precision
必填:否;声明来源:ASAM 声明。
默认值与来源
未知 / 未声明固定上游文档默认:未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码未声明 default(2.14.7;源码事实,未作为 ASAM 运行实测)
validateEvent
必填:否;声明来源:ASAM 声明。
validateEvent 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
默认值与来源
false(隐式 Boolean 默认;已安装组件)固定上游文档默认:true(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:true(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 运行实测)
align
必填:否;声明来源:ASAM 声明。
align 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:"right" / "left" / "center"
默认值与来源
未知 / 未声明固定上游文档默认:'center'(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:'center'(2.14.7;源码事实,未作为 ASAM 运行实测)
disabledScientific
必填:否;声明来源:ASAM 声明。
disabledScientific 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
默认值与来源
false(隐式 Boolean 默认;已安装组件)固定上游文档默认:false(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 运行实测)
tabindex
必填:否;声明来源:ASAM 声明。
默认值与来源
未知 / 未声明固定上游文档默认:0(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:0(2.14.7;源码事实,未作为 ASAM 运行实测)
AsamInputNumberProps 公开类型视图
import type { AsamInputNumberProps, AsamControlSize } from '@asam-ui/ui';
// AsamInputNumberProps
type PublicContract = {
readonly "id"?: string | undefined;
readonly "step"?: number | undefined;
readonly "stepStrictly"?: boolean | undefined;
readonly "max"?: number | undefined;
readonly "min"?: number | undefined;
readonly "modelValue"?: number | null | undefined;
readonly "readonly"?: boolean | undefined;
readonly "disabled"?: boolean | undefined;
readonly "size"?: AsamControlSize | undefined;
readonly "controls"?: boolean | undefined;
readonly "controlsPosition"?: "" | "right" | undefined;
readonly "valueOnClear"?: number | "max" | "min" | null | undefined;
readonly "name"?: string | undefined;
readonly "placeholder"?: string | undefined;
readonly "precision"?: number | undefined;
readonly "validateEvent"?: boolean | undefined;
readonly "ariaLabel"?: string | undefined;
readonly "inputmode"?: "text" | "email" | "search" | "tel" | "url" | "none" | "numeric" | "decimal" | undefined;
readonly "align"?: "right" | "left" | "center" | undefined;
readonly "disabledScientific"?: boolean | undefined;
readonly "formatter"?: ((value: string) => string) | undefined;
readonly "parser"?: ((value: string) => string) | undefined;
readonly "tabindex"?: string | number | undefined;
};
参数与事件说明
update:modelValue
必填:是;声明来源:ASAM 声明。
change
必填:是;声明来源:ASAM 声明。
input
必填:是;声明来源:ASAM 声明。
focus
必填:是;声明来源:ASAM 声明。
blur
必填:是;声明来源:ASAM 声明。
AsamInputNumberEmits 公开类型视图
import type { AsamInputNumberEmits } from '@asam-ui/ui';
// AsamInputNumberEmits
type PublicContract = {
"update:modelValue": [value: number | null | undefined];
"change": [value: number | null | undefined, previousValue: number | null | undefined];
"input": [value: number | null | undefined];
"focus": [event: FocusEvent];
"blur": [event: FocusEvent];
};
参数与事件说明
prefix
必填:否;声明来源:ASAM 声明。
prefix 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(): unknown
suffix
必填:否;声明来源:ASAM 声明。
suffix 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(): unknown
increase-icon
必填:否;声明来源:ASAM 声明。
increase-icon 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(): unknown
decrease-icon
必填:否;声明来源:ASAM 声明。
decrease-icon 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(): unknown
AsamInputNumberSlots 公开类型视图
import type { AsamInputNumberSlots } from '@asam-ui/ui';
// AsamInputNumberSlots
type PublicContract = {
"prefix"?: (() => unknown) | undefined;
"suffix"?: (() => unknown) | undefined;
"increase-icon"?: (() => unknown) | undefined;
"decrease-icon"?: (() => unknown) | undefined;
};
参数与事件说明
focus
必填:是;声明来源:ASAM 声明。
focus 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(): void
blur
必填:是;声明来源:ASAM 声明。
blur 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(): void
AsamInputNumberExpose 公开类型视图
import type { AsamInputNumberExpose } from '@asam-ui/ui';
// AsamInputNumberExpose
type PublicContract = {
"focus": () => void;
"blur": () => void;
};