# @desource/phone-mask-svelte 中文文档

规范地址：https://npmcn.com/package/%40desource/phone-mask-svelte/

版本：2\.1\.0
npm 元数据更新时间：2026-11-07T02:46:24.931Z
中文译文更新时间：2026-11-12T01:34:05.356Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40desource/phone-mask-svelte
原文对照：https://npmcn.com/package/%40desource/phone-mask-svelte/?lang=original
项目主页：https://github.com/DeSource-Labs/phone-mask/tree/main/packages/svelte#readme
源码仓库：https://github.com/DeSource-Labs/phone-mask

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：122 kB，37 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- 运行依赖：1 个
- peer 依赖：svelte ^5\.0\.0
- 首次发布：2026-03-06T16:42:29.384Z
- 最新版本发布：2026-11-07T02:46:24.504Z
- 近 30 天下载量：19699（2026-10-12 至 2026-11-10，npm 官方下载统计）
- 已发布版本数：18（近 12 个月 18 个）

## 中文简介

🌍 Svelte 5 组件,可编程,动作和附件用于国际电话号码口罩. 由@desource/ phone- mask提供, 并同步 Google libphone 数字.

## 安装

```sh
npm install @desource/phone-mask-svelte
```

也可以使用：`pnpm add @desource/phone-mask-svelte`、`yarn add @desource/phone-mask-svelte`、`bun add @desource/phone-mask-svelte`

## README

# @ desource/ phone- massk- svelte (英语)

> 带有 Google libphone 数字数据的 Svelte 5 电话输入组件

[![npm version](https://img.shields.io/npm/v/@desource/phone-mask-svelte?color=blue&logo=svelte)](https://www.npmjs.com/package/@desource/phone-mask-svelte) [![code coverage](https://img.shields.io/codecov/c/gh/DeSource-Labs/phone-mask?logo=codecov)](https://codecov.io/gh/DeSource-Labs/phone-mask) [![SonarCloud](https://sonarcloud.io/api/project_badges/measure?project=DeSource-Labs_phone-mask&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=DeSource-Labs_phone-mask) [![Ask CodeWiki](https://img.shields.io/badge/Ask%20CodeWiki-007af4?logo=googlegemini&logoColor=white)](https://codewiki.google/github.com/desource-labs/phone-mask) [![Ask Context7](https://img.shields.io/badge/Ask%20Context7-059669.svg?logo=data:image/svg%2bxml;base64,PHN2ZyB3aWR0aD0iMjgiIGhlaWdodD0iMjgiIHZpZXdCb3g9IjAgMCAyOCAyOCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTI0IDBINEMxLjc5MDg2IDAgMCAxLjc5MDg2IDAgNFYyNEMwIDI2LjIwOTEgMS43OTA4NiAyOCA0IDI4SDI0QzI2LjIwOTEgMjggMjggMjYuMjA5MSAyOCAyNFY0QzI4IDEuNzkwODYgMjYuMjA5MSAwIDI0IDBaIiBmaWxsPSIjRjdGMkU4IiBmaWxsLW9wYWNpdHk9IjAuNjUiLz4KPHBhdGggZD0iTTEwLjYgMTUuMjk5MkMxMC42IDE3LjQ5OTIgOS43MDAwNSAxOS4zOTkyIDguMjAwMDUgMjEuMDk5MkgxMS42VjIyLjc5OTJINi4zMDAwNVYyMS4xOTkyQzguMDAwMDUgMTkuMzk5MiA4LjYwMDA1IDE3Ljg5OTIgOC42MDAwNSAxNS4yOTkySDEwLjZaTTE3LjQgMTUuMjk5MkMxNy40IDE3LjQ5OTIgMTguMyAxOS4zOTkyIDE5LjggMjEuMDk5MkgxNi40VjIyLjc5OTJIMjEuN1YyMS4xOTkyQzIwIDE5LjM5OTIgMTkuNCAxNy44OTkyIDE5LjQgMTUuMjk5MkgxNy40Wk0xMC42IDEyLjY5OTJDMTAuNiAxMC40OTkyIDkuNzAwMDUgOC41OTkyMiA4LjIwMDA1IDYuODk5MjJIMTEuNlY1LjE5OTIySDYuMzAwMDVWNi43OTkyMkM4LjAwMDA1IDguNTk5MjIgOC42MDAwNSAxMC4wOTkyIDguNjAwMDUgMTIuNjk5MkgxMC42Wk0xNy40IDEyLjY5OTJDMTcuNCAxMC40OTkyIDE4LjMgOC41OTkyMiAxOS44IDYuODk5MjJIMTYuNFY1LjE5OTIySDIxLjdWNi43OTkyMkMyMCA4LjU5OTIyIDE5LjQgMTAuMDk5MiAxOS40IDEyLjY5OTJIMTcuNFoiIGZpbGw9ImJsYWNrIi8+Cjwvc3ZnPgo=)](https://context7.com/desource-labs/phone-mask) [![Ask DeepWiki](https://img.shields.io/badge/Ask%20DeepWiki-1c398e.svg?logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0OCA0OCIgZmlsbD0iI2NiY2JjYiIgYXJpYS1oaWRkZW49InRydWUiPjxwYXRoIGQ9Ik0xOC42IDIwLjFxMS0uNiAyLjItLjZoLjNhNCA0IDAgMCAxIDIgLjdoLjJ2LjFsMSAxaC4xdi4yaC4xbC4xLjF2LjFxLjcgMSAuNyAyLjN0LS42IDIuMnYuMWwtLjIuMkE0IDQgMCAwIDEgMjMgMjhoLS4ydi4xbC0xLjQuNGgtLjVxLTEuMyAwLTIuMy0uNWwtNC4xLTIuNC04LjMgNC44djkuNWw4LjMgNC44IDguMi00LjhWMzVxMC0xLjIuNi0yLjJ2LS4xbC4yLS4yYTQgNCAwIDAgMSAxLjctMS41bDEuMy0uNGguNnExLjMgMCAyLjMuNmw0LjIgMi4zIDguMi00Ljd2LTkuNmwtOC4yLTQuNy00LjIgMi4zcS0xIC42LTIuMi42aC0uM2E0IDQgMCAwIDEtMi0uNmwtLjItLjEtMS0xaC0uMXYtLjJoLS4xbC0uMS0uMnYtLjFxLS43LTEtLjctMi4yVjguMmwtOC4yLTQuNy04LjMgNC43djkuNWw4LjIgNC44eiIvPjwvc3ZnPg==)](https://deepwiki.com/DeSource-Labs/phone-mask) [![license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/DeSource-Labs/phone-mask/blob/main/LICENSE)

美丽可及 极小可树可摇动 Svelte 5 手机输入 自动格式化 国家选择器 验证.

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

升级到 2. 0. 0 之前,审查 [1.7.0的移徙](https://github.com/DeSource-Labs/phone-mask/blob/main/packages/svelte/CHANGELOG.md#migration-from-170) 用于断开更改和需要更新.

## \* 特性

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

## \* 安装

```bash
npm install @desource/phone-mask-svelte
# or
yarn add @desource/phone-mask-svelte
# or
pnpm add @desource/phone-mask-svelte
```

## QQ 快速启动

### 导入

组件模式 :

```ts
import { PhoneInput } from '@desource/phone-mask-svelte';
import '@desource/phone-mask-svelte/assets/lib.css'; // Import styles
```

可编译模式 :

```ts
import { usePhoneMask } from '@desource/phone-mask-svelte';
```

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

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

附件模式(用于现有 `<input>` 元素,要求Svelte 5.29+:

```ts
import { phoneMaskAttachment as phoneMask } from '@desource/phone-mask-svelte';
```

行动模式(用于现有 `<input>` 元素,与所有 Svelte 5 版本一起工作 :

```ts
import { phoneMaskAction as phoneMask } from '@desource/phone-mask-svelte';
```

### 组件模式

```svelte
<script lang="ts">
  import { PhoneInput } from '@desource/phone-mask-svelte';
  import '@desource/phone-mask-svelte/assets/lib.css';

  let phone = $state('');
  let isValid = $state(false);
</script>

<PhoneInput bind:value={phone} country="US" onvalidationchange={(v) => (isValid = v)} />

{#if isValid}
  <p>✓ Valid phone number</p>
{/if}
```

### 可编译模式

关于自定义输入执行:

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

  let value = $state('');

  const phoneMask = usePhoneMask({
    value: () => value,
    onChange: (digits) => (value = digits),
    country: () => 'US',
    detect: () => false
  });
</script>

<div>
  <input bind:this={phoneMask.inputRef} type="tel" placeholder="Phone number" />
  <p>Formatted: {phoneMask.fullFormatted}</p>
  <p>Valid: {phoneMask.isComplete ? 'Yes' : 'No'}</p>
  <p>Country: {phoneMask.country.name}</p>
  <button onclick={() => phoneMask.setCountry('GB')}>Use UK</button>
</div>
```

### 附件模式

用于现有 `<input>` 没有折叠组件的元素。 需要斯维尔特5.29+.

```svelte
<script lang="ts">
  import { phoneMaskAttachment as phoneMask } from '@desource/phone-mask-svelte';
  import type { PMaskPhoneNumber, PMaskFull } from '@desource/phone-mask-svelte';

  let country = $state('US');

  function handleChange(phone: PMaskPhoneNumber) {
    console.log('Full:', phone.full, 'Digits:', phone.digits);
  }

  function handleCountryChange(c: PMaskFull) {
    console.log('Country:', c.name);
  }
</script>

<div class="phone-wrapper">
  <select bind:value={country}>
    <option value="US">🇺🇸 +1</option>
    <option value="GB">🇬🇧 +44</option>
    <option value="DE">🇩🇪 +49</option>
  </select>

  <input
    {@attach phoneMask({ country, onChange: handleChange, onCountryChange: handleCountryChange })}
    placeholder="Phone number"
  />
</div>
```

短手( 国家代码字符串 ):

```svelte
<input {@attach phoneMask('US')} />
```

自动检测:

```svelte
<input {@attach phoneMask({ detect: true, onChange: handleChange })} />
```

### 行动模式

用于现有 `<input>` 没有折叠组件的元素。 与 **所有 Svelte 5 版本** (包括5.29前). 反应参数变化通过Svelte 应用 `use:` 动作 `update()` 寿命轮钩.

```svelte
<script lang="ts">
  import { phoneMaskAction as phoneMask } from '@desource/phone-mask-svelte';
  import type { PMaskPhoneNumber, PMaskFull } from '@desource/phone-mask-svelte';

  let country = $state('US');

  function handleChange(phone: PMaskPhoneNumber) {
    console.log('Full:', phone.full, 'Digits:', phone.digits);
  }

  function handleCountryChange(c: PMaskFull) {
    console.log('Country:', c.name);
  }
</script>

<div class="phone-wrapper">
  <select bind:value={country}>
    <option value="US">🇺🇸 +1</option>
    <option value="GB">🇬🇧 +44</option>
    <option value="DE">🇩🇪 +49</option>
  </select>

  <input
    use:phoneMask={{ country, onChange: handleChange, onCountryChange: handleCountryChange }}
    placeholder="Phone number"
  />
</div>
```

短手( 国家代码字符串 ):

```svelte
<input use:phoneMask={'US'} />
```

自动检测:

```svelte
<input use:phoneMask={{ detect: true, onChange: handleChange }} />
```

### 发送 Raw 数字到后端

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

  let digits = $state('');

  async function handlePhoneChange(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>

<PhoneInput bind:value={digits} country="US" onchange={handlePhoneChange} />
```

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

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

  let selectedCountry = $state<PCountryKey>('US');
  let digits = $state('');

  const phoneMask = usePhoneMask({
    value: () => digits,
    onChange: (value) => (digits = value),
    country: () => selectedCountry
  });

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

<select
  value={selectedCountry}
  onchange={(e) => onCountrySelect((e.currentTarget as HTMLSelectElement).value as PCountryKey)}
>
  <option value="US">US</option>
  <option value="GB">GB</option>
  <option value="DE">DE</option>
</select>

<input bind:this={phoneMask.inputRef} type="tel" />
<p>{phoneMask.fullFormatted}</p>
<p>{phoneMask.isComplete ? 'complete' : 'incomplete'}</p>
```

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

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

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

  let { tenantId }: { tenantId: string } = $props();

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

  const policy = $derived(TENANT_POLICIES[tenantId] ?? { defaultCountry: 'US' as const });
  let digits = $state('');

  const phoneMask = usePhoneMask({
    value: () => digits,
    onChange: (value) => (digits = value),
    country: () => policy.defaultCountry
  });

  const isTenantValid = $derived(
    phoneMask.isComplete && (policy.prefixRule ? policy.prefixRule.test(phoneMask.digits) : true)
  );
</script>

<input bind:this={phoneMask.inputRef} type="tel" />
<p>Default country: {policy.defaultCountry}</p>
<p>Tenant validation: {isTenantValid ? 'pass' : 'fail'}</p>
```

## ++ 显示格式

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

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

  let { phone }: { phone: string } = $props();
</script>

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

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

该功能在SSF期间有效. 不支持的值保持不变; 空白, 仅空白, `null`,以及 `undefined` 值返回空文本。 见 [格式规则](https://github.com/DeSource-Labs/phone-mask/blob/main/packages/core/README.md#formatphonevalue-country-options) 用于检测限度和实例.

## \* 构件 API

### 道具

> **说明:** 该组件支持控制模式和可约束模式。 使用 `bind:value` 用于双向绑定或 `value` + 键 `onchange` 用于控制模式.

```ts
interface PhoneInputProps {
  // Bindable value (digits only, without country code)
  value?: 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

  // Extra CSS class merged onto root element
  class?: string;

  // Callback when the phone number changes.
  // 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)
  onchange?: (value: PhoneNumber) => void;

  // Callback when the selected country changes
  oncountrychange?: (country: MaskFull) => void;

  // Callback when the validation state changes
  onvalidationchange?: (isValid: boolean) => void;

  // Callback when the input is focused
  onfocus?: (event: FocusEvent) => void;

  // Callback when the input is blurred
  onblur?: (event: FocusEvent) => void;

  // Callback when phone number is copied
  oncopy?: (value: string) => void;

  // Callback when input is cleared
  onclear?: () => void;
}
```

### 被曝光的方法

通过 `bind:this`数字 :

```svelte
<script lang="ts">
  import { PhoneInput } from '@desource/phone-mask-svelte';
  import type { PhoneInputExposed } from '@desource/phone-mask-svelte';

  let phoneInput = $state<PhoneInputExposed | null>(null);
</script>

<PhoneInput bind:this={phoneInput} />
<button onclick={() => phoneInput?.focus()}>Focus</button>
```

```ts
interface PhoneInputExposed {
  focus: () => void; // Focus the input
  blur: () => void; // Blur the input
  clear: () => void; // Clear the input value
  selectCountry: (code: string) => void; // Programmatically select a country by ISO code
  getFullNumber: () => string; // Returns full phone number with country code (e.g. +1234567890)
  getFullFormattedNumber: () => string; // Returns formatted number with country code (e.g. +1 234-567-890)
  getDigits: () => string; // Returns only digits without country code (e.g. 234567890)
  isValid: () => boolean; // Checks if the current phone number is valid
  isComplete: () => boolean; // Alias for isValid()
}
```

### 片断

```svelte
<PhoneInput bind:value={phone}>
  {#snippet flag(country)}
    <img src="/flags/{country.code.toLowerCase()}.svg" alt={country.name} />
  {/snippet}

  {#snippet copysvg(copied)}
    {copied ? '✓' : '📋'}
  {/snippet}

  {#snippet clearsvg()}
    ✕
  {/snippet}

  {#snippet actionsbefore()}
    <button onclick={handleCustomAction}>Custom</button>
  {/snippet}
</PhoneInput>
```

| 片断 | 道具 | 说明 |
| --- | --- | --- |
| `flag` | `MaskFull` | 自定义国家列表和选择器中的旗帜图标 |
| `copysvg` | `boolean` (复制状态) | 自定义复制按钮图标 |
| `clearsvg` | —— 说 | 自定义清除按钮图标 |
| `actionsbefore` | —— 说 | 默认动作按钮前的内容 |

## ++可编译的 API

### 选项

> **说明:** 可混凝土功能用于反应性选项. 不要直接传递值.

```ts
interface UsePhoneMaskOptions {
  // Getter returning current digit value (controlled) - REQUIRED
  value: () => string;

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

  // Getter for ISO country code (e.g., 'US', 'DE', 'GB')
  country?: () => string | undefined;

  // Getter for locale string (default: navigator.language)
  locale?: () => string | undefined;

  // Getter for auto-detect flag (default: false)
  detect?: () => boolean | undefined;

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

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

### 返回值

> **重要内容:** 不要对返回对象进行分解——所有属性都是被动取出器和分解断裂反应.

```ts
interface UsePhoneMaskReturn {
  // Ref to attach to your input element
  inputRef: HTMLInputElement | null;

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

  // Phone formatter instance
  formatter: FormatterHelpers;

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

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

  // Whether the phone number is complete
  isComplete: boolean;

  // Whether the input is empty
  isEmpty: boolean;

  // Whether to show validation warning
  shouldShowWarn: boolean;

  // Current country data
  country: MaskFull;

  // Current locale used for country names
  locale: string;

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

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

```svelte
<script lang="ts">
  // ✅ CORRECT — access as properties
  const phoneMask = usePhoneMask(options);
  phoneMask.digits;

  // ❌ WRONG — loses reactivity
  const { digits } = usePhoneMask(options);
</script>
```

## 附录 API

这个 `phoneMaskAttachment` Svelte附件(Svelte 5.29+)直接适用于任何 `<input>` 元素通过 `{@attach phoneMaskAttachment(...)}`不同 `use:` 当呼叫站点中的反应状态发生变化时,附件厂会重新进行反应运行——没有手动操作 `update()` 需要帮助.

### 基本用途

```svelte
<script lang="ts">
  import { phoneMaskAttachment } from '@desource/phone-mask-svelte';
</script>

<input {@attach phoneMaskAttachment('US')} />
```

### 选项

```ts
import type { PMaskFull, PMaskPhoneNumber } from '@desource/phone-mask-svelte';

interface PhoneMaskBindingOptions {
  // 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;
}
```

参数可以是国家代码字符串(shorthand)或选项对象:

```svelte
<!-- Shorthand -->
<input {@attach phoneMaskAttachment('DE')} />

<!-- Full options -->
<input {@attach phoneMaskAttachment({ country: 'DE', onChange: handleChange })} />

<!-- Auto-detect -->
<input {@attach phoneMaskAttachment({ detect: true, onCountryChange: handleCountryChange })} />
```

### 反应国

直接通过反应状态——工厂在 `selectedCountry` 变化 :

```svelte
<script lang="ts">
  import { phoneMaskAttachment as phoneMask } from '@desource/phone-mask-svelte';

  let selectedCountry = $state('US');
  let phoneData = $state<{ full: string; digits: string } | null>(null);
</script>

<select bind:value={selectedCountry}>
  <option value="US">🇺🇸 United States</option>
  <option value="GB">🇬🇧 United Kingdom</option>
  <option value="DE">🇩🇪 Germany</option>
</select>

<input {@attach phoneMask({ country: selectedCountry, onChange: (p) => (phoneData = p) })} placeholder="Phone number" />
```

## 行动 API

这个 `phoneMaskAction` Svelte动作将手机口罩直接应用到任何 `<input>` 元素通过 `use:phoneMaskAction`它与 **所有 Svelte 5 版本** ——不需要斯维尔特5.29+.

当绑定参数对象发生变化时(例如一个新的) `country` 值, Svelte 自动调用动作的 `update()` 钩子,可以重新应用新的选项,必要时可以切换国家.

### 基本用途

```svelte
<script lang="ts">
  import { phoneMaskAction } from '@desource/phone-mask-svelte';
</script>

<input use:phoneMaskAction={'US'} />
```

### 选项

```ts
import type { PMaskFull, PMaskPhoneNumber } from '@desource/phone-mask-svelte';

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

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

  // Auto-detect country from GeoIP on mount; falls back to locale detection
  detect?: boolean;

  // Value change callback — fires on every phone number change
  onChange?: (phone: PMaskPhoneNumber) => void;

  // Country change callback — fires on initial mount and on country switch
  onCountryChange?: (country: PMaskFull) => void;
}
```

参数可以是国家代码字符串(shorthand)或选项对象:

```svelte
<!-- Shorthand -->
<input use:phoneMaskAction={'DE'} />

<!-- Full options -->
<input use:phoneMaskAction={{ country: 'DE', onChange: handleChange }} />

<!-- Auto-detect -->
<input use:phoneMaskAction={{ detect: true, onCountryChange: handleCountryChange }} />
```

### 反应国

被动通过 `$state` 在选项对象内——斯维尔特调用 `update()` 当 `selectedCountry` 变化 :

```svelte
<script lang="ts">
  import { phoneMaskAction as phoneMask } from '@desource/phone-mask-svelte';

  let selectedCountry = $state('US');
  let phoneData = $state<{ full: string; digits: string } | null>(null);
</script>

<select bind:value={selectedCountry}>
  <option value="US">🇺🇸 United States</option>
  <option value="GB">🇬🇧 United Kingdom</option>
  <option value="DE">🇩🇪 Germany</option>
</select>

<input use:phoneMask={{ country: selectedCountry, onChange: (p) => (phoneData = p) }} placeholder="Phone number" />
```

### 动作对附件

|  | `use:phoneMaskAction` | `{@attach phoneMaskAttachment(...)}` |
| --- | --- | --- |
| 需要斯维尔特版本 | 全斯维尔特5 | 丝绒 5.29+ |
| 反应机制 | `update()` 钩(自发) | 工厂进行反应式再运行 |
| 手动 `update()` 需求 | 不(Svelte处理它) | 没有 |

## 组件样式

### CSS 自定义属性

通过 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);
}
```

### 黑暗主题

```svelte
<PhoneInput bind:value={phone} theme="dark" />
```

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

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

## 实例

### 有验证

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

  let phone = $state('');
  let isValid = $state(false);

  const errorMessage = $derived(!phone ? '' : isValid ? '' : 'Please enter a valid phone number');
</script>

<div>
  <PhoneInput bind:value={phone} country="US" onvalidationchange={(v) => (isValid = v)} />

  {#if errorMessage}
    <span class="error">{errorMessage}</span>
  {/if}
</div>
```

### 自动检测国家

```svelte
<script lang="ts">
  import { PhoneInput } from '@desource/phone-mask-svelte';
  import type { PMaskFull } from '@desource/phone-mask-svelte';

  let phone = $state('');
  let detectedCountry = $state('');

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

<PhoneInput bind:value={phone} detect oncountrychange={handleCountryChange} />

{#if detectedCountry}
  <p>Detected: {detectedCountry}</p>
{/if}
```

### 程序控制

```svelte
<script lang="ts">
  import { PhoneInput } from '@desource/phone-mask-svelte';
  import type { PhoneInputExposed } from '@desource/phone-mask-svelte';

  let phone = $state('');
  let phoneInput = $state<PhoneInputExposed | null>(null);
</script>

<PhoneInput bind:this={phoneInput} bind:value={phone} />

<div>
  <button onclick={() => phoneInput?.focus()}>Focus</button>
  <button onclick={() => phoneInput?.clear()}>Clear</button>
  <button onclick={() => phoneInput?.selectCountry('GB')}>Switch to UK</button>
  <p>Full: {phoneInput?.getFullFormattedNumber()}</p>
  <p>Valid: {phoneInput?.isValid()}</p>
</div>
```

### 多个输入

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

  let form = $state({ mobile: '', home: '', work: '' });
</script>

<div class="form">
  <label>
    Mobile
    <PhoneInput bind:value={form.mobile} country="US" />
  </label>

  <label>
    Home
    <PhoneInput bind:value={form.home} country="US" />
  </label>

  <label>
    Work
    <PhoneInput bind:value={form.work} country="US" />
  </label>
</div>
```

### 自定义可编译执行

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

  let inputValue = $state('');
  let selectedCountry = $state('US');

  const phoneMask = usePhoneMask({
    value: () => inputValue,
    country: () => selectedCountry,
    detect: () => false,
    onChange: (digits) => {
      inputValue = digits;
    },
    onPhoneChange: (data: PMaskPhoneNumber) => {
      console.log('Phone:', data.fullFormatted);
    }
  });
</script>

<div class="custom-phone">
  <select bind:value={selectedCountry}>
    <option value="US">🇺🇸 +1</option>
    <option value="GB">🇬🇧 +44</option>
    <option value="DE">🇩🇪 +49</option>
  </select>

  <input bind:this={phoneMask.inputRef} type="tel" placeholder="Phone number" />
</div>

<p>Formatted: {phoneMask.fullFormatted}</p>
<p>Valid: {phoneMask.isComplete ? 'Yes' : 'No'}</p>
<p>Country: {phoneMask.country.name}</p>
```

## QQ 浏览器支持

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

## 包含什么

```
@desource/phone-mask-svelte/
├── dist/
│   ├── index.js               # Main Svelte package entry
│   ├── index.d.ts             # Root TypeScript declarations
│   ├── components/
│   │   └── PhoneInput.svelte  # Consumer-compiled Svelte component
│   ├── core.js                # Core kit utilities and mask data subpath
│   ├── core.d.ts              # Core subpath declarations
│   ├── phone-mask-svelte.css  # Component styles
│   └── ...                    # Supporting modules and colocated declarations
├── README.md                  # This file
└── package.json               # Package manifest
```

包运本地的 Svelte 组件和 rune 模块, 因此您的 Svelte 构建为浏览器或服务器 。 它需要Svelte-aware工具;没有预编集的CommonJS组件条目.

## 有关软件包

-   [@ desource/ phone- mask (英语)](https://github.com/DeSource-Labs/phone-mask/blob/main/packages/core) - 核心图书馆
-   [@ desource/ phone- mask- angular (英语)](https://github.com/DeSource-Labs/phone-mask/blob/main/packages/angular) - 角装订
-   [@ desource/ phone- mask- react](https://github.com/DeSource-Labs/phone-mask/blob/main/packages/react) - 反应约束
-   [@ desource/ phone- mask- vue](https://github.com/DeSource-Labs/phone-mask/blob/main/packages/vue) - Vue 3装订
-   [@ desource/ phone- mask- nuxt](https://github.com/DeSource-Labs/phone-mask/blob/main/packages/nuxt) - 努克特模块

## 许可证

[麻省理工学院](https://github.com/DeSource-Labs/phone-mask/blob/main/LICENSE) 2026 来源实验室

## 捐款

见 [贡献指南](https://github.com/DeSource-Labs/phone-mask/blob/main/CONTRIBUTING.md) 用于开发、测试和出版检查.

* * *

由 Q 制作 [来源实验室](https://github.com/DeSource-Labs)

## 常见问题

### @desource/phone-mask-svelte 是什么？

🌍 Svelte 5 组件,可编程,动作和附件用于国际电话号码口罩\. 由@desource/ phone- mask提供, 并同步 Google libphone 数字\.

### 如何安装 @desource/phone-mask-svelte？

在项目目录运行 npm install @desource/phone-mask-svelte，或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖：svelte（^5\.0\.0）。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖，Yarn 需要手动安装。

### @desource/phone-mask-svelte 支持 TypeScript 吗？

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

### @desource/phone-mask-svelte 支持 ESM 还是 CommonJS？

以 ES Module 形式发布，推荐使用 import 引入。在 CommonJS 项目中，Node\.js 20\.19\+ / 22\.12\+ 可以直接 require\(\) 不含顶层 await 的 ES Module，更早的版本需要改用动态 import\(\)。

### @desource/phone-mask-svelte 可以商用吗？

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

### @desource/phone-mask-svelte 的下载量有多少？

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

### @desource/phone-mask-svelte 还在维护吗？

最新版本 2\.1\.0 发布于 2026/11/07（4 天前）；至今共发布 18 个版本，其中过去 12 个月发布了 18 个；首次发布于 2026/03/07。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

