InputNumber 数字输入框
受控的数值录入控件。所有写回都经过同一套 parse → clamp → precision → commit 流程,因此外部拿到的 modelValue 永远是「合法且在区间内」的值,业务侧不必再做一次校验与取整。
代码演示
基础用法
v-model 绑定 number | null,默认步进 1,min / max 会把越界值收敛到边界。
<script setup lang="ts">
import { ref } from 'vue'
const quantity = ref<number | null>(1)
</script>
<template>
<div class="m-row-demo">
<MInputNumber v-model="quantity" :min="1" :max="10" clearable />
</div>
</template>控制器布局
controls="right" 在右侧并排上下箭头,controls="both" 在左右两侧放减号与加号。
<script setup lang="ts">
import { ref } from 'vue'
const rightControls = ref<number | null>(3)
const bothControls = ref<number | null>(3)
</script>
<template>
<div class="m-row-demo">
<MInputNumber v-model="rightControls" controls="right" />
<MInputNumber v-model="bothControls" controls="both" />
</div>
</template>上下限
到达边界后对应的步进按钮会自动禁用,手动输入越界数字也会被收敛。
<script setup lang="ts">
import { ref } from 'vue'
const percent = ref<number | null>(50)
</script>
<template>
<div class="m-row-demo">
<MInputNumber v-model="percent" :min="0" :max="100" :step="5" controls="both" />
</div>
</template>精度与步长
precision 在小数录入、金额计算这类场景下避免浮点尾数;step 支持小数。
第一个输入框把 change 抛出的值弹成 toast,可以直观看到精度归一化后的结果。
<script setup lang="ts">
import { ref } from 'vue'
import { toast } from 'miao-design'
const price = ref<number | null>(9.9)
function onChange(value: number | null) {
toast.info(`外部收到的值:${value}`)
}
</script>
<template>
<div class="m-row-demo--col">
<MInputNumber
v-model="price"
:precision="2"
:step="0.5"
:min="0"
controls="both"
width="200px"
@change="onChange" />
<MInputNumber v-model="price" :precision="2" :step="0.5" :min="0" width="200px" />
</div>
</template>尺寸
与 MInput 同体系,高度取全局 --m-size-* 令牌。
<script setup lang="ts">
import { ref } from 'vue'
const small = ref<number | null>(1)
const normal = ref<number | null>(2)
const large = ref<number | null>(3)
</script>
<template>
<div class="m-row-demo--col">
<MInputNumber v-model="small" size="small" :min="0" />
<MInputNumber v-model="normal" size="default" :min="0" />
<MInputNumber v-model="large" size="large" :min="0" />
</div>
</template>清空、只读与禁用
clearable 清空后把值置为 null 并重新聚焦;只读与禁用都会同时停用步进按钮。
非数字输入会在失焦时被解析成 null。
<script setup lang="ts">
import { ref } from 'vue'
import { toast } from 'miao-design'
const editable = ref<number | null>(12)
const readonlyValue = ref<number | null>(256)
function onChange(value: number | null) {
toast.info(value === null ? '外部收到 null(清空或非数字输入)' : `外部收到 ${value}`)
}
</script>
<template>
<div class="m-row-demo--col">
<MInputNumber v-model="editable" clearable :min="0" :max="100" @change="onChange" />
<MInputNumber v-model="readonlyValue" readonly />
<MInputNumber :model-value="128" :min="0" disabled />
</div>
</template>API
Props
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
modelValue | number | null | undefined(未提供) | 数值(v-model);空值传 undefined / null 均可 |
placeholder | string | undefined(未提供) | 占位文本 |
disabled | boolean | false | 是否禁用 |
readonly | boolean | false | 是否只读 |
clearable | boolean | false | 是否显示清除按钮 |
size | 'small' | 'default' | 'large' | 'default' | 高度取全局 --m-size-* 令牌:small 28px / default 36px / large 48px |
controls | 'right' | 'both' | 'right' | 步进按钮布局:right 右侧并排(down / up 箭头)/both 左右两侧(减号 / 加号) |
min | number | undefined(内部按 -Infinity) | 最小值 |
max | number | undefined(内部按 +Infinity) | 最大值 |
step | number | 1 | 步进值 |
precision | number | undefined(未提供) | 显示精度,归一化时按该精度四舍五入 |
width | string | undefined(未提供;样式默认 180px) | 宽度 |
MInputNumber 没有 radius 属性,圆角固定取全局令牌 --m-radius。
Events
| 事件 | 参数 | 说明 |
|---|---|---|
update:modelValue | value: number | null | 值变化(清空或非法输入为 null) |
focus | event: FocusEvent | 聚焦 |
blur | event: FocusEvent | 失焦 |
change | value: number | null | 归一化后的值发生变化时触发(失焦 / 步进 / 清空) |
clear | 无 | 点击清除按钮 |
Slots
无。
类型定义
export type InputNumberControls = 'right' | 'both';
// size 复用 InputSize = 'small' | 'default' | 'large'InputNumberControls 未从包入口导出
miao-design 的入口只再导出了 MInputNumberProps,InputNumberControls 这个类型别名不在入口的导出清单里。需要标注类型时,直接写字面量 'right' | 'both',或者用索引访问 MInputNumberProps['controls']。
使用建议
回车提交,Escape 放弃
输入框内的值在失焦时才会写回外部。为了避免「输入后按回车看着生效、外部还是旧值」,组件额外支持:回车立即提交,Escape 放弃本次编辑回到外部传入的值。键盘上下键也可以步进。
空值与非法输入的语义
空字符串、纯空格、Number() 解析为 NaN 的输入都会在提交时变成 null,而不是 0。如果业务需要一个非空默认值,请在提交前兜底(例如 value ?? 0)。
change 只在值真正变化时抛
commit() 内部比较归一化后的值与原 modelValue,相同则不抛 update:modelValue / change。因此「输入 10 再失焦」「输入 11 被 max=10 收敛回 10」都不会产生事件,不要依赖 change 计数。
相关组件
- Input 输入框:自由文本录入。
- Slider 滑动条:需要连续拖拽调值时比步进按钮更顺手。
- Select 选择器:取值来自固定选项集合时改用下拉。