andr-04/jquery.inputmask-multi

Inputmask Multi 是一个插件,允许根据输入数据的前缀选择输入掩码(例如国际电话号码)

安装次数: 9,698

依赖关系: 1

建议者: 0

安全性: 0

星标: 253

关注者: 18

分支: 106

开放问题: 15

语言:JavaScript

1.2.0 2016-03-07 14:49 UTC

This package is not auto-updated.

Last update: 2024-09-28 18:37:11 UTC


README

=============== Inputmask Multi

此插件是为 jQuery 开发的,允许根据输入的电话号码前缀选择输入掩码。这种技术可以减少输入电话号码时的错误,并使其更加简单。此外,此插件还可以用于其他字段,其中输入规则可以表示为多个输入掩码。

简介

网站通常需要输入电话号码。如今,每个国家都有自己的拨号规则和号码长度。因此,不同国家的人在使用电话号码时容易混淆:一个人给出的号码从数字 8 开始,另一个人从 0 开始,第三个人从 + 开始。

现有解决方案的评估

为解决上述问题并统一电话号码格式,有三种主要解决方案可用

  1. 建议使用输入掩码输入电话号码。优点:电话号码的直观显示可以减少输入错误。缺点:每个国家都有自己的电话号码书写规则,长度不同。

  2. 建议选择国家并输入电话号码的剩余部分;也可以为电话号码的剩余部分使用输入掩码。优点:可以为每个国家(以及国家内的每个地区)使用不同的输入掩码。缺点:国家(以及每个国家内的地区)的列表可能很长;电话号码被分成两部分(在保存和显示电话号码之前需要额外的预处理)。

  3. 在电话号码前添加数字 +(在输入框外),并允许仅输入数字。优点:易于实现。缺点:电话号码没有直观的显示。

解决方案

因此,决定改进常用的输入掩码,使其根据已输入的电话号码进行更改。此外,建议在输入电话号码时显示国家(地区)名称。主观上,这种方法应该解决上述所有问题。

考虑到世界上有那么多国家,决定收集所有国家的输入掩码列表。电话号码规则的信息来源是国际电信联盟网站发布的信息

收集这些信息的过程很复杂。需要考虑所有可能的电话号码情况,包括每个国家内部的差异。由于手动处理了大量的信息,因此收集的数据可能包含不准确之处。计划在以后的时间内对此进行修复。

实现

本项目使用的是 jquery.inputmask 的实现。此插件仍在持续开发中,并旨在使其能够为其编写扩展。但在本任务中,无法编写扩展。我决定不涉及或重写核心的源代码,以避免由于它持续开发而引起的任何冲突,因此我不得不编写一个核心的超级结构来监控(并中断)外部事件以更改数据。在核心之前嵌入外部事件处理器的插件是 jquery.bind-first

允许输入的掩码排序

要选择一个比其他电话号码匹配度更高的输入掩码,必须以特殊方式对所有可能的掩码列表进行排序。在考虑规则时,接受了以下定义

  1. 掩码中的所有符号分为两类:重要符号(在我的情况下是符号 #,它匹配任何数字,以及数字 0-9)和符号装饰器(所有其他符号)。

  2. 输入掩码中符号的另一种分割是模板符号(在我的情况下是符号 #)和其他符号。

因此,编写了以下应用顺序的排序规则

  1. 比较两个输入掩码时,仅考虑重要符号(不是装饰器)。

  2. 不同的模板符号被视为等效,其他重要符号根据它们的代码进行比较。

  3. 非模板符号始终小于模板符号,并且它们在结果中位于上方。

  4. 输入掩码中的重要字符长度越短,输入掩码越小,并且位于结果上方。

搜索匹配的输入掩码

当将输入文本与排序列表中的每个输入掩码进行比较时,仅考虑输入掩码中的重要符号。如果文本比掩码长,尽管所有之前的掩码符号都匹配,此掩码也不匹配。如果输入文本与多个掩码匹配,则仅返回第一个。之后,将找到的掩码中的所有重要符号(包括非模板符号)替换为模板符号,该模板符号结合了任何模板符号允许的所有符号。

事件处理和操作

为了避免与核心处理器的冲突,以下事件被中断

  • keydown - 监控 Backspace 和 Delete 键的按下,以便在核心处理器删除文本中的一个符号之前更改当前输入掩码。此外,还监控 Insert 键的按下,以更改输入模式进行同步。

  • keypress - 由于输入的符号可能不允许原始掩码(因为所有重要符号都被替换为模板),需要检查新文本是否与允许的输入掩码匹配。如果找不到匹配的掩码,则取消输入的符号,否则更改当前输入掩码,并将此事件传递到核心。

  • pasteinput - 从剪贴板粘贴文本。在将事件传递到核心之前,对新的文本进行掩码搜索。如果找不到输入掩码,则从文本末尾开始按符号剪切,直到找到匹配的掩码。此方法用于更改文本的 val() 函数之后,以及初始化时如果输入文本不为空也是如此。

  • dragdrop(拖放)和 drop(放下)的处理与粘贴相同。

  • blur - 当输入框失去焦点且不匹配输入掩码时,进行额外的处理。此事件在核心事件处理之后处理。

所有事件都在 inputmask 空间中处理。这允许在初始化此插件后调用 inputmask 方法时避免错误操作(因为核心的初始化会取消 inputmask 空间中的其他处理程序)。

使用示例

掩码列表的格式

掩码列表是一个包含具有相同(或类似)属性集的对象的 JavaScript 数组。数组中的所有对象都必须至少有一个包含输入掩码的属性。此属性的名称可以不同。以下是一个掩码列表的示例片段

[
…
	{ "mask": "+7(###)###-##-##", "cc": "RU", "name_en": "Russia", "desc_en": "", "name_ru": "Россия", "desc_ru": "" },
	{ "mask": "+250(###)###-###", "cc": "RW", "name_en": "Rwanda", "desc_en": "", "name_ru": "Руанда", "desc_ru": "" },
	{ "mask": "+966-5-####-####", "cc": "SA", "name_en": "Saudi Arabia ", "desc_en": "mobile", "name_ru": "Саудовская Аравия ", "desc_ru": "мобильные" },
	{ "mask": "+966-#-###-####", "cc": "SA", "name_en": "Saudi Arabia", "desc_en": "", "name_ru": "Саудовская Аравия", "desc_ru": "" },
…
]

插件连接参数

在使用插件之前,需要对掩码列表进行排序。可以通过调用以下函数来完成此操作

$.masksSort = function(maskList, defs, match, key)
  • maskList - 输入掩码对象的数组(见上方);
  • defs - 模板符号的数组(在我们的案例中是符号 #);
  • match - 有效符号的正则表达式(在我们的案例中是 /[0-9]|#/);
  • key - 包含输入掩码的数组对象中的属性名称。

在插件初始化时,传递一个设置其工作的对象。此对象包含以下参数集

  • inputmask - 核心插件的参数对象;
  • match - 除去模板符号之外的有效符号的正则表达式;
  • replace - 将所有有效符号替换掉的模板符号;可以在输入掩码对象的定义对象中省略;
  • list - 输入掩码对象的数组;
  • listKey - 包含输入掩码的对象中的属性名称;
  • onMaskChange - 当更新当前输入掩码时调用的函数(回调函数);第一个参数是一个包含适配掩码的对象,第二个参数是新掩码的精度:true - 掩码完全适配,false - 需要更多符号来确定真正的掩码。

要初始化插件,需要调用输入字段的 inputmasks:$.fn.inputmasks = function(maskOpts, mode)

  • maskOpts - 设置插件工作的对象;
  • mode - 可选;现在它可以具有值 isCompleted - 如果输入字段的文本已完全输入,则函数返回 true,在其他情况下返回 false。

插件使用示例

<input type="text" id="customer_phone" value="7" size="25"><br>
<input type="checkbox" id="phone_mask" checked>
<label id="descr" for="phone_mask">Маска ввода</label>
<script>
	var maskList = $.masksSort($.masksLoad("phone-codes.json"), ['#'], /[0-9]|#/, "mask");
	var maskOpts = {
		inputmask: {
			definitions: {
				'#': {
					validator: "[0-9]",
					cardinality: 1
				}
			},
			//clearIncomplete: true,
			showMaskOnHover: false,
			autoUnmask: true
		},
		match: /[0-9]/,
		replace: '#',
		list: maskList,
		listKey: "mask",
		onMaskChange: function(maskObj, completed) {
			if (completed) {
				var hint = maskObj.name_ru;
				if (maskObj.desc_ru && maskObj.desc_ru != "") {
					hint += " (" + maskObj.desc_ru + ")";
				}
				$("#descr").html(hint);
			} else {
				$("#descr").html("Маска ввода");
			}
			$(this).attr("placeholder", $(this).inputmask("getemptymask"));
		}
	};

	$('#phone_mask').change(function() {
		if ($('#phone_mask').is(':checked')) {
			$('#customer_phone').inputmasks(maskOpts);
		} else {
			$('#customer_phone').inputmask("+[####################]", maskOpts.inputmask)
			.attr("placeholder", $('#customer_phone').inputmask("getemptymask"));
			$("#descr").html("Маска ввода");
		}
	});

	$('#phone_mask').change();
</script>

演示

此插件的演示可在项目的 页面 上找到。