【免费下载链接】imaskjs
vanilla javascript input mask
导读
本指南以 vue-imask(IMask 的 Vue 官方适配包,版本 7.6.1)为核心,系统讲解在 Vue 2 与 Vue 3 项目中接入输入掩码(Input Mask)的三种官方方式:IMaskComponent 组件、IMaskDirective 指令、以及面向 Vue 3 的 useIMask Composable。读完本文,你将掌握 v-model 双向绑定的数据形态(masked / unmasked / typed)、accept / complete 事件体系、全部 mask 参数(数字、日期、模式、枚举、动态掩码等)的传法,并能直接照着示例在项目中落地电话、日期、金额、手机号等格式化输入场景。文中涉及的全部实现细节均可对照本仓库 vue-imask 源码 与 imask 核心源码 验证。
安装与环境适配
npm i vue-imask
vue-imask 通过 vue-demi 中的 isVue3 ? Component3 : Component2 判断)。其依赖声明为 vue >= 2.7(见 package.json 的 peerDependencies),因此 Vue 2 项目需要确保版本不低于 2.7。
Vue 2 补充安装
如果使用 Vue 2,还需要额外安装 Composition API 桥接包:
npm i -D @vue/composition-api
NuxtJS(Vue 2)补充配置
如果使用 NuxtJS 且基于 Vue 2,还需要安装 Nuxt 版的 Composition API 模块:
npm i -D @nuxtjs/composition-api
然后在 nuxt.config.js 的 buildModules 中加入 @nuxtjs/composition-api/module:
export default {
buildModules: [
// ...
'@nuxtjs/composition-api/module'
]
}
方式一:<imask-input> 组件
IMaskComponent 在内部渲染一个原生 <input>,所有 mask 参数与原生 input 属性(如 placeholder)可以直接写在组件上。组件同时支持 Vue 2 的 Options API 与 Vue 3 的 Composition API 实现:Vue 3 走 component3-composition.ts,Vue 2 走 component2.ts(另有 Options API 版 component3-options.ts)。
Vue 2 示例:数字掩码
<template>
<imask-input
v-model="numberModel"
:mask="Number"
radix="."
:unmask="true"
@accept="onAccept"
<!-- 其余 mask 参数见下文参数总表 -->
placeholder='Enter number here'
/>
</template>
<script>
import { IMaskComponent } from 'vue-imask';
export default {
data () {
return {
numberModel: '',
onAccept (value) {
console.log(value);
}
}
},
components: {
'imask-input': IMaskComponent
}
}
</script>
需要特别留意 unmask 与 @accept 回调第一个参数的对应关系(README 官方说明):
unmask=false时,@accept的第一个参数是value(带掩码的显示值);unmask=true时,第一个参数是unmaskedValue(去掉掩码后的纯值);unmask='typed'时,第一个参数是typedValue(类型化后的值,例如Number掩码下是数字而非字符串)。
Vue 2 组件内部通过 _maskValue() 实现这一映射(component2.ts):当 unmask === 'typed' 返回 maskRef.typedValue,为真时返回 unmaskedValue,否则返回 value;_onAccept 会同时向外派发 input 与 accept 事件(component2.ts)。
Vue 3 示例:typed 双向绑定与细分事件
Vue 3 组件支持多种 v-model 写法,README 明确指出:v-model 等价于 v-model:value、v-model:masked 和 v-model:unmasked,此外还有独立的 v-model:typed:
<template>
<imask-input
v-model:typed="numberModel"
:mask="Number"
radix="."
@accept:masked="onAccept"
@accept:unmasked="onAcceptUnmasked"
<!--
@accept:typed="onAcceptTyped"
@complete:typed="onCompleteTyped"
-->
placeholder='Enter number here'
/>
</template>
<script>
import { IMaskComponent } from 'vue-imask';
export default {
data () {
return {
numberModel: '',
onAccept (value) {
console.log({ value });
},
onAcceptUnmasked (unmaskedValue) {
console.log({ unmaskedValue });
}
}
},
components: {
'imask-input': IMaskComponent
}
}
</script>
Vue 3 组件对外派发的事件全表(见 component3-composition.ts 的 emits 声明):
| 事件 | 说明 |
|---|---|
accept / accept:value / accept:masked | 接受输入时派发,参数为带掩码的显示值 |
accept:unmasked | 接受输入时派发,参数为去掩码值 |
accept:typed | 接受输入时派发,参数为类型化值 |
complete / complete:value / complete:masked | 输入完整(达到掩码完整长度)时派发 |
complete:unmasked / complete:typed | 输入完整时派发对应的 unmasked / typed 值 |
update:modelValue / update:value / update:masked | 组件内部维护显示值同步,供 v-model 使用 |
update:unmasked / update:typed | 同步 unmasked / typed 值,供 v-model:unmasked / v-model:typed 使用 |
从源码看,accept 与 complete 的派发逻辑并不相同:onAccept 会一次性把 masked、unmasked、typed 三种形态全部派发出去(component3-composition.ts),而 onComplete 只额外派发 complete:value(同 complete:masked),complete:unmasked 与 complete:typed 则由 useIMask 内部完整派发(见 composable.ts)。这意味着 Vue 3 的组件与 Composable 两套 API 在事件细分上由同一套核心逻辑支撑。
数值型 v-model 的值优先级
VALUE_PROPS 数组 ['typed', 'unmasked', 'value', 'modelValue'](component3-composition.ts)定义了同步优先级:同时传入多个值时,typed 优先,其次 unmasked、value、modelValue。初始化时组件按此优先级取初始值写入掩码(component3-composition.ts)。可以推断:业务中推荐只绑定一种值形态(通常是最符合业务语义的 typed 或 unmasked),避免多值同时写入导致互相覆盖。
方式二:v-imask 指令
指令适合对既有 <input>(或 contenteditable 元素)直接施加掩码,无需替换成组件。README 特别提醒:指令场景下 v-model 绑定可能不生效,应通过 @accept 或 @complete 事件手动更新值。指令派发的是原生 CustomEvent,事件对象上的 e.detail 即 mask 实例引用(见 directive.ts 的 fireEvent 实现),从中可读取 value、unmaskedValue、typedValue 等属性。
<template>
<input
:value="value"
v-imask="mask"
@accept="onAccept"
@complete="onComplete">
</template>
<script>
import { IMaskDirective } from 'vue-imask';
export default {
data () {
return {
value: '',
mask: {
mask: '{8}000000',
lazy: false
},
},
},
methods: {
onAccept (e) {
const maskRef = e.detail;
this.value = maskRef.value;
console.log('accept', maskRef.value);
},
onComplete (e) {
const maskRef = e.detail;
console.log('complete', maskRef.unmaskedValue);
},
},
directives: {
imask: IMaskDirective
}
}
</script>
上例的 {8}000000 是模式掩码:{8} 为固定文本(必须原样输入 8),0 为数字占位符。因为设置了 lazy: false,输入过程中会即时显示 _ 占位。
指令的生命周期映射(directive.ts):
- Vue 3 的
beforeMount/ Vue 2 的bind:挂载时调用initMask创建掩码; updated/update:当指令绑定的 options 变化时调用maskRef.updateOptions()热更新掩码配置,若 options 变为空值则销毁掩码(可用来实现"启用/禁用掩码"切换);unmounted/unbind:销毁掩码并解绑事件。
仓库自带的 example.html 中就有"Disable/Enable mask"按钮,通过把 v-imask 绑定的对象置空来开关日期掩码的完整示例。
方式三:useIMask Composable(Vue 3)
Composable 适合在 <script setup> / Composition API 场景下把掩码绑定到任意元素 ref 上,是三者中与原生模板结构耦合最低的方式:
<template>
<input ref="el">
</template>
<script>
import { useIMask } from 'vue-imask';
export default {
setup (props) {
const { el, masked } = useIMask({
mask: Number,
radix: '.',
}, /* 可选参数 {
emit,
onAccept,
onComplete,
defaultValue,
defaultUnmaskedValue,
defaultTypedValue,
} */);
return { el };
}
}
</script>
useIMask 的完整签名与返回值(composable.ts):
- 第一参数:掩码配置
FactoryOpts,也可以是Ref<FactoryOpts>,因此配置可随 ref 响应式更新; - 第二参数(可选):
ComposableParams,包含emit、onAccept、onComplete回调,以及defaultValue、defaultUnmaskedValue、defaultTypedValue三个默认值注入点; - 返回值:
el(元素 ref,绑定到模板)、mask(只读的 mask 实例 ref)、masked/unmasked/typed(三种数据形态的响应式 ref)。
useIMask 的内部机制值得展开:它通过 onMounted 创建掩码、onUnmounted 销毁(composable.ts),并 watch 元素与配置,元素变化时自动重建、配置变化时调用 updateOptions 热更新(composable.ts)。三个响应式 ref 与 mask 实例之间是双向同步的:外部写入 ref 会写回 mask 实例并触发 accept 重放,mask 内部变化又会回写 ref(storeLastAcceptedValues 与三个 update*Value watch 共同完成这一闭环,见 composable.ts)。
README 注释中标出的可选参数 emit 值得注意:组件正是把 emit 注入 useIMask 后,才统一获得了 accept:masked / accept:typed / complete:unmasked 等全套细分事件能力(见 composable.ts 的 _onAccept / _onComplete)。也就是说,组件 API 实际上是 Composable API 的薄封装——理解了 useIMask,就理解了组件的事件模型。
Mask 参数总表(组件 / 指令 / Composable 通用)
所有 mask 配置均来自 imask 核心的 FactoryOpts 类型(factory.ts),vue-imask 将其展开为组件 props(props.ts)。按掩码类型分组如下:
通用参数(所有掩码类型)
| 参数 | 类型 | 说明 |
|---|---|---|
mask | string \| RegExp \| Number \| Date \| Array \| Function \| Masked 实例/类 | 掩码定义,决定掩码类型(见下文映射表) |
prepare | Function | 在掩码处理前整体转换值(如大小写、去空格) |
prepareChar | Function | 对输入值逐字符转换(如把小写字母转大写) |
validate | Function | 自定义校验函数,返回 false 则拒绝输入 |
commit | Function | 编辑结束时对值做额外处理(如补零、四舍五入) |
overwrite | boolean \| 'shift' | 允许覆盖输入('shift' 表示右移覆盖) |
eager | boolean \| 'append' \| 'remove' | 是否即时显示完整占位('append' / 'remove' 控制光标方向),props 层校验见 props.ts |
skipInvalid | boolean | 是否跳过非法输入(核心默认值为 true,见 base.ts) |
autofix | boolean \| 'pad' | 编辑结束时自动修正(日期掩码下 'pad' 表示补齐位数) |
模式掩码(mask 为字符串)
| 参数 | 说明 |
|---|---|
placeholderChar | 空输入的占位字符,默认 _(pattern.ts) |
displayChar | 已填充字符的显示字符(用于密码类场景统一显示为 • 等) |
lazy | 是否仅在有需要时显示占位,默认 true |
definitions | 自定义占位符定义,如 { '#': /[0-9]/ } |
blocks | 模式中的块配置,如日期掩码中 d/m/Y 各块的取值范围 |
模式掩码的占位符语义:0 数字、a 字母、* 任意字符,\ 转义、` 为停止字符;{固定文本} 表示必须原样出现的文本(pattern.ts)。自定义 definitions 时键值为单个字符,值为正则、字符串或 Masked 类/实例(pattern.ts)。
数字掩码(mask 为 Number)
| 参数 | 默认值 | 说明 |
|---|---|---|
radix | , | 小数点分隔符 |
thousandsSeparator | '' | 千分位分隔符 |
mapToRadix | ['.'] | 输入时可映射为小数点的字符集合(默认支持英文句点) |
scale | 2 | 小数点后位数 |
min | Number.MIN_SAFE_INTEGER | 最小值 |
max | Number.MAX_SAFE_INTEGER | 最大值 |
normalizeZeros | true | 编辑结束时是否去除前导/尾随零 |
padFractionalZeros | false | 编辑结束时是否补齐小数位零 |
以上默认值均来自 number.ts 的 MaskedNumber.DEFAULTS。README 示例中的 radix="." 即为指定小数点显示与输入均为英文句点。
日期掩码(mask 为 Date)
| 参数 | 说明 |
|---|---|
pattern | 日期模式,默认 d{.}m{.}Y(即 dd.mm.yyyy,见 date.ts) |
format / parse | 自定义格式/解析函数(提供自定义 pattern 时必填,见 date.ts 的 RequiredDateOptions) |
min / max | 允许的最小/最大日期(Date 或可解析值) |
autofix | 是否在编辑结束时自动补齐/修正日期 |
日期掩码默认块:d 取值 1-31(2 位)、m 取值 1-12(2 位)、Y 取值 1900-9999(date.ts),均为 MaskedRange 实现。
枚举 / 范围 / 动态掩码
| 掩码类型 | mask 值 | 关键参数 |
|---|---|---|
| 枚举 | 数组(如 ['张三', '李四']) | enum(候选列表)、可选 matchValue(enum.ts) |
| 范围 | 数值区间 | from / to / maxLength(见 range.ts 与 props.ts) |
| 动态 | Array 构造器或掩码数组 | dispatch:根据输入动态选择掩码(dynamic.ts) |
此外 mask 还可为 RegExp(正则掩码)或函数(自定义函数掩码)。mask 类型到 Masked 类的完整映射逻辑在 factory.ts 的 maskedClass 中:字符串 → MaskedPattern、Number → MaskedNumber、Date → MaskedDate、数组/Array → MaskedDynamic、RegExp → MaskedRegExp、函数 → MaskedFunction。
参数透传与优先级细节
组件的 mask 参数通过 extractOptionsFromProps(utils.ts)从 props 中抽取,该函数会剔除值为 undefined 的 prop 以及 value / unmask 等绑定专用 prop,避免把 Vue 的绑定值误当作掩码配置传给 imask。Vue 3 组件还通过 VALUE_PROPS 过滤出绑定专用 prop(component3-composition.ts)。这意味着:未传的 mask 参数会落入 imask 核心默认值,传入的才生效——在排查"参数没生效"问题时,应优先检查 props 拼写与绑定值是否为 undefined。
常见业务场景速查
以下三个场景可组合上文参数直接使用:
手机号/固定文本前缀(模式掩码)
<imask-input v-model="phone" :mask="{ mask: '+{7}00000000000', lazy: false }" />
金额输入(数字掩码,保留 2 位小数、千分位)
<imask-input
v-model:typed="amount"
:mask="Number"
radix="."
thousands-separator=","
scale="2"
pad-fractional-zeros
/>
注:Vue 模板中
thousandsSeparator等驼峰 prop 需写作thousands-separator;padFractionalZeros可写作pad-fractional-zeros。
日期输入(Vue 3 组合式 API)
<template>
<input ref="dateEl" />
</template>
<script setup>
import { useIMask } from 'vue-imask';
const { el: dateEl, typed } = useIMask({
mask: Date,
pattern: 'd{.}`m{.}`Y',
autofix: 'pad'
}, {
defaultTypedValue: new Date()
});
</script>
与 imask 核心的关系
vue-imask 只是 imask 的 Vue 绑定层:核心掩码引擎位于 packages/imask,vue-imask 的三种 API 最终都会调用核心 IMask(element, opts) 工厂创建掩码实例(组件在 component2.ts / component3-options.ts、指令在 directive.ts、Composable 在 composable.ts),并订阅实例的 accept / complete 事件。因此核心 imask 的所有能力(模式、数字、日期、动态、枚举、范围、正则、函数掩码)都通过这三个 API 暴露给 Vue 应用。
vue-imask 的导出面(index.ts)包括:IMaskComponent、IMaskDirective、useIMask(含 ComposableParams 等类型)与 IMaskProps。若需要在 Vue 中直接操作 Masked 实例的底层 API(如 masked.value 的精细读取与写入),也可从同一入口导出 IMask 核心对象使用。更完整的掩码语义说明(各 Masked 类的行为与全部选项)可参考根目录 README.md 及 docs/guide.html 中关于 imask 核心的指南部分。
【免费下载链接】imaskjs
vanilla javascript input mask
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



