Vue IMask 集成指南:组件、指令与 Composable 三种方式实现输入掩码

  • 前端
  • UI组件

【免费下载链接】imaskjs

vanilla javascript input mask

项目地址: https://gitcode.com/gh_mirrors/im/imaskjs
点击查看 免费下载

导读

本指南以 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)。按掩码类型分组如下:

通用参数(所有掩码类型)

参数类型说明
maskstring \| RegExp \| Number \| Date \| Array \| Function \| Masked 实例/类掩码定义,决定掩码类型(见下文映射表)
prepareFunction在掩码处理前整体转换值(如大小写、去空格)
prepareCharFunction对输入值逐字符转换(如把小写字母转大写)
validateFunction自定义校验函数,返回 false 则拒绝输入
commitFunction编辑结束时对值做额外处理(如补零、四舍五入)
overwriteboolean \| 'shift'允许覆盖输入('shift' 表示右移覆盖)
eagerboolean \| 'append' \| 'remove'是否即时显示完整占位('append' / 'remove' 控制光标方向),props 层校验见 props.ts
skipInvalidboolean是否跳过非法输入(核心默认值为 true,见 base.ts)
autofixboolean \| '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['.']输入时可映射为小数点的字符集合(默认支持英文句点)
scale2小数点后位数
minNumber.MIN_SAFE_INTEGER最小值
maxNumber.MAX_SAFE_INTEGER最大值
normalizeZerostrue编辑结束时是否去除前导/尾随零
padFractionalZerosfalse编辑结束时是否补齐小数位零

以上默认值均来自 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 核心的指南部分。

  • 前端
  • UI组件

【免费下载链接】imaskjs

vanilla javascript input mask

项目地址: https://gitcode.com/gh_mirrors/im/imaskjs
点击查看 免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值