@desource/phone-mask-vue

中文文档
2.1.0发布于 2026/11/07MITTypeScriptESM + CJS构建来源已验证近 30 天下载 2万

Vue 3组件,可调和,以及用于国际电话号码口罩的指令. 由@desource/ phone- mask提供, 并同步 Google libphone 数字.

中文使用文档
文档目录38 节
  1. * 特性
  2. * 安装
  3. QQ 快速启动
  4. 导入
  5. 组件模式
  6. 指令模式
  7. 可编译模式
  8. 发送 Raw 数字到后端
  9. 关于国家变化的动态遮罩更新
  10. 多租户:租户Id 默认国家+特定租户审定规则
  11. ++ 显示格式
  12. * 构件 API
  13. 道具
  14. 活动
  15. 被曝光的方法
  16. 槽数
  17. 使用参考文献
  18. 组件样式
  19. CSS 自定义属性
  20. 黑暗主题
  21. 指令 API
  22. 基本用途
  23. 有选项
  24. 反应国
  25. ++可编译的 API
  26. usePhoneMask
  27. 选项
  28. 返回值
  29. 实例
  30. 有验证
  31. 自动检测国家
  32. 带有窗体库
  33. 多个输入
  34. QQ 浏览器支持
  35. 包含什么
  36. 有关软件包
  37. 许可证
  38. 捐款

@ desource/ phone- mask- vue

Vue 3 有 Google 的 libphone 数字数据的电话输入组件

npm version code coverage SonarCloud Ask CodeWiki Ask Context7 Ask DeepWiki license

美丽可及,极小可树可摇动的Vue 3手机输入,并带有自动格式化,国家选择器,以及验证功能.

粘贴完整的国际编号,首先是 + 检测其国家,并用数字取代输入,而不使用其调用代码。 检测使用掩码格式化,再用数字计数;模棱两可的匹配使用调用代码的默认国家. 没有调用代码的碎片保持了正常的插入行为. 这个 detect 选项分别控制 GeoIP 检测.

升级到 2. 0. 0 之前,审查 1.7.0的移徙 用于断开更改和需要更新.

* 特性

  • 🌐 安保部门支助 —— 说 PhoneInput 在服务器上使 HTML 格式化,并在浏览器中使水合物格式化
  • 🎨 美丽的UI ——以轻/暗为主题的现代设计
  • 🔍 智能国家搜索 ——模糊匹配键盘导航
  • 🎭 自动格式化 ——有智能光标的现用类型格式
  • ✅ 验证 ——内设有视觉反馈的验证
  • 📋 复制按钮 — 一击副本到剪贴板
  • 🌐 自动检测 ——地生化和地生化探测
  • ♿ 可访问 ——ARIA标签,键盘导航
  • 📱 便于移动 - 优化触摸装置
  • 🎯 类型脚本 - 全套安全
  • 🧩 三种模式 - 组件、可混合或指令
  • ⚡ 优化 - 树摇和代码分割

* 安装

npm install @desource/phone-mask-vue
# or
yarn add @desource/phone-mask-vue
# or
pnpm add @desource/phone-mask-vue

QQ 快速启动

导入

组件模式 :

import { createApp } from 'vue';
import { PhoneInput } from '@desource/phone-mask-vue';
import '@desource/phone-mask-vue/assets/lib.css'; // Import styles

const app = createApp(App);
app.component('PhoneInput', PhoneInput);
app.mount('#app');

指令模式(用于自定义输入执行):

import { createApp } from 'vue';
import { vPhoneMask } from '@desource/phone-mask-vue';

const app = createApp(App);
app.directive('phone-mask', vPhoneMask);
app.mount('#app');

可编译模式(用于自定义输入执行,以防甚至指令都不符合您的需要):

import { usePhoneMask } from '@desource/phone-mask-vue';

从核心包子路径再出口的核心工具包和掩码数据:

import { getFlagEmoji, formatDigitsWithMap } from '@desource/phone-mask-vue/core';

全部同时注册( 组件+指令) :

import { createApp } from 'vue';
import phoneMask from '@desource/phone-mask-vue';
import '@desource/phone-mask-vue/assets/lib.css'; // Import styles for component mode

const app = createApp(App);
app.use(phoneMask); // Registers component and directive
app.mount('#app');

组件模式

<script setup lang="ts">
import { ref } from 'vue';
import { PhoneInput } from '@desource/phone-mask-vue';

const phoneDigits = ref('');
const isValid = ref(false);
</script>

<template>
  <PhoneInput v-model="phoneDigits" country="US" theme="light" @validation-change="isValid = $event" />

  <p v-if="isValid">✓ Valid phone number</p>
</template>

指令模式

对于自动格式化的自定义样式:

<script setup lang="ts">
import { ref } from 'vue';
import type { PMaskPhoneNumber } from '@desource/phone-mask-vue';

const country = ref('US');
const phone = ref('');
const digits = ref('');

const handleChange = (nextPhone: PMaskPhoneNumber) => {
  phone.value = nextPhone.full;
  digits.value = nextPhone.digits;
};
</script>

<template>
  <div class="phone-wrapper">
    <select v-model="country">
      <option value="US">🇺🇸 +1</option>
      <option value="GB">🇬🇧 +44</option>
      <option value="DE">🇩🇪 +49</option>
    </select>

    <input
      v-phone-mask="{
        country,
        onChange: handleChange
      }"
      placeholder="Phone number"
    />
  </div>

  <p>{{ digits }} digits entered</p>
</template>

可编译模式

对于自定义输入执行(如果甚至指令也不符合您的需要):

<script setup lang="ts">
import { ref } from 'vue';
import { usePhoneMask } from '@desource/phone-mask-vue';

const value = ref('');

const { inputRef, digits, full, fullFormatted, isComplete, setCountry } = usePhoneMask({
  value,
  onChange: (newValue) => (value.value = newValue),
  country: 'US',
  detect: true
});
</script>

<template>
  <div>
    <input ref="inputRef" type="tel" placeholder="Phone number" />
    <p>Formatted: {{ fullFormatted }}</p>
    <p>Valid: {{ isComplete ? 'Yes' : 'No' }}</p>
    <button @click="setCountry('GB')">Use UK</button>
  </div>
</template>

发送 Raw 数字到后端

<script setup lang="ts">
import { ref } from 'vue';
import { PhoneInput, type PMaskPhoneNumber } from '@desource/phone-mask-vue';

const phoneDigits = ref('');

const onPhoneChange = async (phone: PMaskPhoneNumber) => {
  await fetch('/api/profile/phone', {
    method: 'POST',
    headers: { 'content-type': 'application/json' },
    body: JSON.stringify({
      phoneDigits: phone.digits, // unformatted value for backend
      phoneFull: phone.full // optional full number with country code
    })
  });
};
</script>

<template>
  <PhoneInput v-model="phoneDigits" country="US" @change="onPhoneChange" />
</template>

关于国家变化的动态遮罩更新

<script setup lang="ts">
import { ref } from 'vue';
import { usePhoneMask, type PCountryKey } from '@desource/phone-mask-vue';

const selectedCountry = ref<PCountryKey>('US');
const digits = ref('');

const { inputRef, fullFormatted, isComplete, setCountry } = usePhoneMask({
  value: digits,
  onChange: (value) => (digits.value = value),
  country: selectedCountry
});

const onCountrySelect = (nextCountry: PCountryKey) => {
  selectedCountry.value = nextCountry;
  setCountry(nextCountry); // updates mask immediately
};
</script>

<template>
  <select :value="selectedCountry" @change="onCountrySelect(($event.target as HTMLSelectElement).value as PCountryKey)">
    <option value="US">US</option>
    <option value="GB">GB</option>
    <option value="DE">DE</option>
  </select>

  <input ref="inputRef" type="tel" />
  <p>{{ fullFormatted }}</p>
  <p>{{ isComplete ? 'complete' : 'incomplete' }}</p>
</template>

多租户:租户Id 默认国家+特定租户审定规则

<script setup lang="ts">
import { computed, ref } from 'vue';
import { usePhoneMask, type PCountryKey } from '@desource/phone-mask-vue';

type TenantPolicy = {
  defaultCountry: PCountryKey;
  prefixRule?: RegExp;
};

const props = defineProps<{ tenantId: string }>();

const TENANT_POLICIES: Record<string, TenantPolicy> = {
  acme: { defaultCountry: 'US', prefixRule: /^(202|303)\d{7}$/ },
  globex: { defaultCountry: 'GB', prefixRule: /^7\d{9}$/ }
};

const tenantPolicy = computed(() => TENANT_POLICIES[props.tenantId] ?? { defaultCountry: 'US' as const });
const digits = ref('');

const {
  inputRef,
  digits: maskDigits,
  isComplete
} = usePhoneMask({
  value: digits,
  onChange: (value) => (digits.value = value),
  country: computed(() => tenantPolicy.value.defaultCountry)
});

const isTenantValid = computed(() => {
  if (!isComplete.value) return false;
  const rule = tenantPolicy.value.prefixRule;
  return rule ? rule.test(maskDigits.value) : true;
});
</script>

<template>
  <input ref="inputRef" type="tel" />
  <p>Default country: {{ tenantPolicy.defaultCountry }}</p>
  <p>Tenant validation: {{ isTenantValid ? 'pass' : 'fail' }}</p>
</template>

++ 显示格式

打电话 formatPhone(value, country?, options?) 直接在模板中。 它返回文本, 不需要 CSS .

<script setup lang="ts">
import { formatPhone } from '@desource/phone-mask-vue/core';

defineProps<{ phone: string }>();
</script>

<template>
  <span>{{ formatPhone(phone, 'US', { code: false, flag: true }) }}</span>
</template>
<!-- '+12345678888' displays as '🇺🇸 234 567 8888'. -->

奥米 country 以检测一个完整的国际编号 +; 传递给没有调用代码的号码, 或解析美国/CA等共享调用代码. 可选 PhoneFormatOptions 参数接受 code (默认) true和 flag (默认) false) (中文(简体) ).

该功能在SSF期间有效. 不支持的值保持不变; 空白, 仅空白, null,以及 undefined 值返回空文本。 见 格式规则 用于检测限度和实例.

* 构件 API

道具

interface PhoneInputProps {
  // v-model binding
  modelValue?: string;

  // Optional id/name applied to the underlying <input> for forms/autofill
  id?: string;
  name?: string;

  // Preselected country (ISO 3166-1 alpha-2)
  country?: CountryKey;

  // Auto-detect country from IP/locale
  detect?: boolean; // Default: true

  // Locale for country names
  locale?: string; // Default: browser language

  // Size variant
  size?: 'compact' | 'normal' | 'large'; // Default: 'normal'

  // Visual theme ("auto" | "light" | "dark")
  theme?: 'auto' | 'light' | 'dark'; // Default: 'auto'

  // Disabled state
  disabled?: boolean; // Default: false

  // Readonly state
  readonly?: boolean; // Default: false

  // Show copy button
  showCopy?: boolean; // Default: true

  // Show clear button
  showClear?: boolean; // Default: false

  // Show validation state (borders & outline)
  withValidity?: boolean; // Default: true

  // Custom search placeholder
  searchPlaceholder?: string; // Default: 'Search country or code...'

  // Custom no results text
  noResultsText?: string; // Default: 'No countries found'

  // Custom clear button label
  clearButtonLabel?: string; // Default: 'Clear phone number'

  // Dropdown menu custom CSS class
  dropdownClass?: string;

  // Disable default styles
  disableDefaultStyles?: boolean; // Default: false
}

活动

interface PhoneInputEvents {
  // v-model update
  'update:modelValue': (value: string) => void;

  // Value changed
  // Provides an object with:
  // - full: Full phone number with country code (e.g. +1234567890)
  // - fullFormatted: Full phone number formatted according to country rules (e.g. +1 234-567-890)
  // - digits: Only the digits of the phone number without country code (e.g. 234567890)
  change: (value: PMaskPhoneNumber) => void;

  // Country changed
  'country-change': (country: PMaskFull) => void;

  // Validation state changed
  'validation-change': (isValid: boolean) => void;

  // Input focused
  focus: (event: FocusEvent) => void;

  // Input blurred
  blur: (event: FocusEvent) => void;

  // Copy button clicked
  copy: (value: string) => void;

  // When input is cleared
  clear: () => void;
}

被曝光的方法

interface PhoneInputExpose {
  // Focus the phone input
  focus: () => void;

  // Blur the phone input
  blur: () => void;

  // Clear the phone input
  clear: () => void;

  // Select a country by its ISO 3166-1 alpha-2 code
  selectCountry: (country: CountryKey) => void;

  // Get the full phone number with country code (e.g. +1234567890)
  getFullNumber: () => string;

  // Get the full phone number formatted according to country rules (e.g. +1 234-567-890)
  getFullFormattedNumber: () => string;

  // Get only the digits of the phone number without country code (e.g. 234567890)
  getDigits: () => string;

  // Check if the current phone number is valid
  isValid: () => boolean;

  // Check if the current phone number is complete
  isComplete: () => boolean;
}

槽数

  • actions-before ——默认按钮前的自定义动作槽

  • flag 国家列表和国家选择器中自定义国家旗帜的显示槽

  • copy-svg ——自定义复制按钮 SVG 图标的槽

  • clear-svg ——自定义清除按钮 SVG 图标的槽

使用参考文献

<script setup lang="ts">
import { ref } from 'vue';
import { PhoneInput } from '@desource/phone-mask-vue';

const phoneInputRef = ref<InstanceType<typeof PhoneInput>>();

const focusInput = () => {
  phoneInputRef.value?.focus();
};

const clearInput = () => {
  phoneInputRef.value?.clear();
};
</script>

<template>
  <PhoneInput ref="phoneInputRef" v-model="phone" />
  <button @click="focusInput">Focus</button>
  <button @click="clearInput">Clear</button>
</template>

组件样式

CSS 自定义属性

通过 CSS 变量自定义颜色 :

.desource-phone-input,
.desource-phone-dropdown {
  /* Colors */
  --pi-bg: #ffffff;
  --pi-fg: #111827;
  --pi-muted: #6b7280;
  --pi-border: #e5e7eb;
  --pi-border-hover: #d1d5db;
  --pi-border-focus: #3b82f6;
  --pi-focus-ring: 3px solid rgb(59 130 246 / 0.15);
  --pi-disabled-bg: #f9fafb;
  --pi-disabled-fg: #9ca3af;
  /* Sizes */
  --pi-font-size: 16px;
  --pi-height: 44px;
  /* Spacing */
  --pi-padding: 12px;
  /* Border radius */
  --pi-radius: 8px;
  /* Shadows */
  --pi-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);
  --pi-shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -2px rgb(0 0 0 / 0.05);
  /* Validation */
  --pi-warning: #f59e0b;
  --pi-warning-light: #fbbf24;
  --pi-success: #10b981;
  --pi-focus-ring-warning: 3px solid rgb(245 158 11 / 0.15);
  --pi-focus-ring-success: 3px solid rgb(16 185 129 / 0.15);
}

黑暗主题

<template>
  <PhoneInput v-model="phone" theme="dark" />
</template>

或与CSS: (中文(简体) )

.desource-phone-input.theme-dark {
  --pi-bg: #1f2937;
  --pi-fg: #f9fafb;
  --pi-border: #374151;
}

指令 API

基本用途

<template>
  <input v-phone-mask="'US'" />
</template>

有选项

interface PMaskDirectiveOptions {
  // Predefined country ISO code (e.g., 'US', 'DE', 'GB')
  country?: string;

  // Locale for country names (default: navigator.language)
  locale?: string;

  // Auto-detect country from IP/locale (default: false)
  detect?: boolean;

  // Value change callback
  onChange?: (phone: PMaskPhoneNumber) => void;

  // Country change callback
  onCountryChange?: (country: PMaskFull) => void;
}
<template>
  <input
    v-phone-mask="{
      country: 'US',
      locale: 'en',
      onChange: handleChange,
      onCountryChange: handleCountryChange
    }"
  />
</template>

反应国

<script setup lang="ts">
import type { PMaskPhoneNumber } from '@desource/phone-mask-vue';

const selectedCountry = ref('US');

const handleChange = (phone: PMaskPhoneNumber) => {
  console.log('Phone:', phone.full, 'Digits:', phone.digits);
};
</script>

<template>
  <select v-model="selectedCountry">
    <option value="US">🇺🇸 United States</option>
    <option value="GB">🇬🇧 United Kingdom</option>
  </select>

  <input
    v-phone-mask="{
      country: selectedCountry,
      onChange: handleChange
    }"
  />
</template>

++可编译的 API

usePhoneMask

关于自定义输入执行:

<script setup lang="ts">
import { ref } from 'vue';
import { usePhoneMask } from '@desource/phone-mask-vue';

const value = ref('');

const { inputRef, digits, full, fullFormatted, isComplete, setCountry, clear } = usePhoneMask({
  value,
  onChange: (newValue) => (value.value = newValue),
  country: 'US',
  detect: false
});
</script>

<template>
  <div>
    <input ref="inputRef" type="tel" />
    <button @click="setCountry('GB')">Switch to UK</button>
    <button @click="clear">Clear</button>
    <p>Full: {{ fullFormatted || '—' }}</p>
    <p>Valid: {{ isComplete ? 'Yes' : 'No' }}</p>
  </div>
</template>

选项

说明: 堆肥需要受控行为. 两者 value 财务报告和审定财务报表 onChange 需要选项.

interface UsePhoneMaskOptions {
  // Controlled value (digits only, without country code) - REQUIRED
  value: MaybeRefOrGetter<string>;

  // Callback when the digits value changes - REQUIRED
  onChange: (digits: string) => void;

  // Predefined country ISO code (e.g., 'US', 'DE', 'GB')
  country?: MaybeRefOrGetter<string | undefined>;

  // Locale for country names (default: navigator.language)
  locale?: MaybeRefOrGetter<string | undefined>;

  // Auto-detect country from IP/locale (default: false)
  detect?: MaybeRefOrGetter<boolean | undefined>;

  // Callback when the phone changes (full, fullFormatted, digits)
  onPhoneChange?: (phone: PhoneNumber) => void;

  // Country change callback
  onCountryChange?: (country: MaskFull) => void;
}

返回值

interface UsePhoneMaskReturn {
  // Ref to attach to your input element
  inputRef: ShallowRef<HTMLInputElement | null>;

  // Raw digits without formatting (e.g., "1234567890")
  digits: ComputedRef<string>;

  // Phone formatter instance
  formatter: ComputedRef<FormatterHelpers>;

  // Full phone number with country code (e.g., "+11234567890")
  full: ComputedRef<string>;

  // Full phone number formatted (e.g., "+1 123-456-7890")
  fullFormatted: ComputedRef<string>;

  // Whether the phone number is complete
  isComplete: ComputedRef<boolean>;

  // Whether the input is empty
  isEmpty: ComputedRef<boolean>;

  // Whether to show validation warning
  shouldShowWarn: ComputedRef<boolean>;

  // Current country data
  country: ComputedRef<MaskFull>;

  // Change country programmatically
  setCountry: (countryCode?: string | null) => boolean;

  // Clear the input
  clear: () => void;
}

实例

有验证

<script setup lang="ts">
import { ref, computed } from 'vue';
import { PhoneInput } from '@desource/phone-mask-vue';

const phone = ref('');
const isValid = ref(false);

const errorMessage = computed(() => {
  if (!phone.value) return '';
  return isValid.value ? '' : 'Please enter a valid phone number';
});
</script>

<template>
  <div>
    <PhoneInput v-model="phone" country="US" @validation-change="isValid = $event" />

    <span v-if="errorMessage" class="error">
      {{ errorMessage }}
    </span>
  </div>
</template>

自动检测国家

<script setup lang="ts">
import { ref } from 'vue';
import { PhoneInput, type PMaskFull } from '@desource/phone-mask-vue';

const phone = ref('');
const detectedCountry = ref('');

const handleCountryChange = (country: PMaskFull) => {
  detectedCountry.value = country.name;
};
</script>

<template>
  <PhoneInput v-model="phone" detect @country-change="handleCountryChange" />

  <p v-if="detectedCountry">Detected: {{ detectedCountry }}</p>
</template>

带有窗体库

维维达德

<script setup lang="ts">
import { useField } from 'vee-validate';
import { PhoneInput } from '@desource/phone-mask-vue';

const { value, errorMessage } = useField('phone', (value) => {
  if (!value) return 'Phone is required';
  // Add custom validation
  return true;
});
</script>

<template>
  <PhoneInput v-model="value" />
  <span v-if="errorMessage">{{ errorMessage }}</span>
</template>

多个输入

<script setup lang="ts">
import { reactive } from 'vue';
import { PhoneInput } from '@desource/phone-mask-vue';

const form = reactive({
  mobile: '',
  home: '',
  work: ''
});
</script>

<template>
  <div class="form">
    <label>
      Mobile
      <PhoneInput v-model="form.mobile" country="US" />
    </label>

    <label>
      Home
      <PhoneInput v-model="form.home" country="US" />
    </label>

    <label>
      Work
      <PhoneInput v-model="form.work" country="US" />
    </label>
  </div>
</template>

QQ 浏览器支持

  • 克罗梅/第90号+
  • Firefox 88+ (英语)
  • 萨法里14+
  • iOS 萨法里14+
  • Chrome 移动

包含什么

@desource/phone-mask-vue/
├── dist/
│   ├── index.mjs           # Main ESM entry
│   ├── index.cjs           # Main CommonJS entry
│   ├── core.mjs            # Core kit utilities and mask data subpath
│   ├── core.cjs            # Core kit utilities and mask data CJS subpath
│   ├── phone-mask-vue.css  # Component styles
│   └── *.d.ts, *.d.cts     # ESM and CommonJS declarations
├── README.md               # This file
└── package.json            # Package manifest

许可证

麻省理工学院 2026 来源实验室

捐款

见 贡献指南 用于开发、测试和出版检查.


由 Q 制作 来源实验室

版本与发布记录

@desource/phone-mask-vue 共发布 26 个版本,首次发布于 2025/11/04;过去 12 个月发布了 24 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
2.1.0latest2026/11/074 天前
2.0.02026/10/3111 天前
1.7.02026/10/101 个月前
1.6.42026/09/261 个月前
1.6.32026/09/082 个月前
1.6.22026/08/242 个月前

其他发布通道:internal-beta → 1.2.1-beta.2。

关于 @desource/phone-mask-vue 的常见问题

@desource/phone-mask-vue 是什么?

Vue 3组件,可调和,以及用于国际电话号码口罩的指令. 由@desource/ phone- mask提供, 并同步 Google libphone 数字.

如何安装 @desource/phone-mask-vue?

在项目目录运行 npm install @desource/phone-mask-vue,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:vue(^3.4.33)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@desource/phone-mask-vue 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@desource/phone-mask-vue 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@desource/phone-mask-vue 可以商用吗?

@desource/phone-mask-vue 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@desource/phone-mask-vue 的下载量有多少?

根据 npm 官方下载统计,@desource/phone-mask-vue 在 2026/10/12 – 2026/11/10 这 30 天内被下载 19,767 次,日均约 659 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@desource/phone-mask-vue 还在维护吗?

最新版本 2.1.0 发布于 2026/11/07(4 天前);至今共发布 26 个版本,其中过去 12 个月发布了 24 个;首次发布于 2025/11/04。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。