Что такое номера по маске. Маскируем и проверяем поле телефона с помощью jQuery

Данный плагин для jQuery позволяет автоматически подбирать подходящую маску ввода на основе введённого начала телефонного номера. Это позволяет сделать ввод номера телефона на странице web-cайта более быстрым и безошибочным. Кроме того, разработанный плагин может быть использован в других областях, если правила ввода возможно представить в виде нескольких масок ввода.

Введение На web-сайтах очень требуется ввод информации о телефонном номере. Так сложилось, что каждая страна вправе устанавливать свои правила набора и длину номера, в результате чего между жителями разных стран периодически возникает путаница: одни привыкли указывать номер с ведущей цифрой 8 , другие - с ведущей цифрой 0 , а третьи - со знака + .Обзор существующих решений Чтобы как-то разрешить возникшую сложность и привести номера к единому формату встречаются 3 основных решения:
  • Пользователю предлагается вводить номер с использованием маски ввода. Преимущество: наглядное отображение номера сводит к минимуму возможные ошибки в номере. Недостаток: в каждой стране принято своё написание и длина номера.
  • Пользователю предлагается отдельно выбирать страну и отдельно вводить оставшуюся часть номера; возможно с применением маски ввода. Преимущество: возможность использования разных масок ввода для разных стран (а также регионов внутри страны). Недостатки: список стран (и регионов внутри каждой страны) может быть большим; номер телефона перестаёт существовать как единое целое (либо требуется предобработка перед сохранением и отображением номера).
  • Поставить знак + перед номером (за пределами input) и разрешить только ввод цифр. Преимущества: простота реализации. Недостаток: отсутствие наглядного отображения номера.
  • Предлагаемое решение В результате было решено доработать привычную маску ввода так, чтобы она менялась в соответствии с текущим значением номера. Кроме того, по мере ввода номера предлагается отображать название определившейся страны. Данный подход, субъективно, должен решить все недостатки перечисленных выше решений.

    С учётом того, что количество стран в мире относительно невелико, было принято решение составить список масок ввода для всех стран. В качестве источника использовались сведения , опубликованные на сайте международного союза электросвязи.

    Сбор данной информации преподнёс немало сюрпризов. В процессе сбора сведений приходилось учитывать все возможные варианты телефонных номеров, в том числе внутри страны. Однако, ввиду большого количества обработанной вручную информации, возможно, в собранной базе остались неточности. С течением времени планируется вносить исправления в первоначальный набор.

    Программная реализация В качестве ядра маски ввода была использована реализация jquery.inputmask , о которой многократно упоминалось на Хабрахабр. Данный плагин сейчас активно развивается и, к тому же, спроектирован таким образом, что для него достаточно просто писать расширения. Однако в данной задаче написать такое расширение оказалось практически невозможно. Я не стал дорабатывать или переписывать исходный плагин под свои нужды, т.к. его автор продолжает активную работу над расширением функционала, в результате чего применение моих правок может оказаться проблематичным. Поэтому мне пришлось написать плагин-надстройку над основным ядром, который отслеживает (плюс перехватывает) внешние воздействия и производит модификацию данных. Для того, чтобы внедрить свои обработчики внешних воздействий до обработчиков основного плагина использовался плагина-библиотека jquery.bind-first .Сортировка разрешённых масок ввода Для корректного выбора наиболее подходящей маски ввода весь набор масок требуется предварительно отсортировать специальным образом. При разработке правил сортировки были приняты следующие условности:
  • Все символы в маске ввода разделены на 2 типа: значимые символы (в моём случае это символ # , означающий произвольную цифру, и цифры 0-9) и символы-декораторы (все остальные).
  • Другое деление символов в маске ввода - это шаблонные символы (в моём случае это символ #) и все остальные.
  • В результате получились следующие правила сортировки в порядке их применения:

  • При посимвольном сравнении 2 масок ввода во внимание принимаются только значимые символы (не декораторы).
  • Разные шаблонные символы воспринимаются как равные, а остальные значимые символы сравниваются на основе их кода.
  • Нешаблонные символы всегда меньше шаблонных и в результате располагаются выше.
  • Чем короче длина значимых символов в маске ввода, тем маска ввода считается меньше и располагается выше.
  • Поиск подходящей маски ввода При сравнении входного текста с очередной маской из отсортированного списка принимаются во внимание только значимые символы каждой маски. Если строка оказывается длиннее маски ввода, несмотря на то что все предшествующие символы прошли проверку, данная маска ввода считается неподходящей. В случае, если входному тексту удовлетворяет несколько масок ввода, то возвращается первая из них. Далее в найденной маске все значимые символы (в том числе нешаблонные) заменяются на шаблонный, который является комбинацией всех символов, разрешённых любым из шаблонных символов.Обработка и перехват событий С целью предотвращения конфликтов с обработчиками событий основного ядра маски ввода перехватываются следующие события:
    • keydown - отслеживаются нажатия клавиш Backspace и Delete - с целью изменения текущей маски ввода перед тем как основной обработчик удалит один символ из текста. Кроме того, отслеживается нажатие клавиши Insert, которая изменяет режим ввода текста, для синхронизации.
    • keypress - поскольку вводимый символ может быть неразрешён оригинальной маской ввода (т.к. все значимые символы в ней заменены на шаблонный), требуется проверить новую строку на удовлетворение одной из разрешённых масок. В случае, если таких масок нет, то ввод символа отбрасывается, иначе - производится обновление маски ввода, после чего событие передаётся обработчику ядра.
    • paste , input - вставка текста из буфера обмена. Перед передачей обработки ядру производится подбор маски ввода для строки, получившейся в результате вставки текста из буфера обмена. В случае, если маску ввода подобрать не удалось, производится посимвольное урезание текста с конца - до тех пор, пока текст не станет удовлетворять хотя бы одной маске ввода. Аналогичная операция производится при исправлении текста в поле ввода вызовом функции val(), а также при инициализации маски ввода, если она применяется к непустому полю ввода.
    • dragdrop , drop - обработка аналогична событию paste.
    • 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 - регулярное выражение, описывающее значимые символы (в моём случае это /|#/);
    • key - имя параметра объекта массива, содержащего маску ввода.

    При подключении плагину передаётся специальный объект, описывающий его работу. Данный объект содержит следующий набор параметров:

    • inputmask - объект, содержащий параметры, передаваемые основному плагину inputmask;
    • match - регулярное выражение, описывающее значимые символы, за исключением шаблонных;
    • replace - шаблонный символ, на который будут заменены все значимые символы; может отсутствовать в объекте definitions объекта inputmask;
    • list - массив объектов, описывающих маски ввода;
    • listKey - имя параметра внутри объекта, хранящего маску ввода;
    • onMaskChange - функция, которая вызывается при обновлении маски ввода; в качестве первого параметра передаётся объект из массива, маска ввода которого соответствует введённому тексту, а в качестве второго - точность определения маски: true - маска ввода соответствует полностью, false - для достоверного определения маски требуется ввод дополнительных символов.

    Для инициализации плагина нужно применить метод inputmasks к полю ввода:
    $.fn.inputmasks = function(maskOpts, mode)

    • maskOpts - объект, описывающий работу плагина;
    • mode - необязательный; в настоящий момент поддерживается значение isCompleted - в результате метод возвращает true , если текст, соответствующей подходящей маске, введён полностью и false в противном случае.
    Пример подключения плагина
    Маска ввода var maskList = $.masksSort($.masksLoad("phone-codes.json"), ["#"], /|#/, "mask"); var maskOpts = { inputmask: { definitions: { "#": { validator: "", cardinality: 1 } }, //clearIncomplete: true, showMaskOnHover: false, autoUnmask: true }, match: //, 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(); Демонстрация Пример демонстрации разработанного плагина представлен на

    Данный плагин для jQuery позволяет автоматически подбирать подходящую маску ввода на основе введённого начала телефонного номера. Это позволяет сделать ввод номера телефона на странице web-cайта более быстрым и безошибочным. Кроме того, разработанный плагин может быть использован в других областях, если правила ввода возможно представить в виде нескольких масок ввода.

    Введение На web-сайтах очень требуется ввод информации о телефонном номере. Так сложилось, что каждая страна вправе устанавливать свои правила набора и длину номера, в результате чего между жителями разных стран периодически возникает путаница: одни привыкли указывать номер с ведущей цифрой 8 , другие - с ведущей цифрой 0 , а третьи - со знака + .Обзор существующих решений Чтобы как-то разрешить возникшую сложность и привести номера к единому формату встречаются 3 основных решения:
  • Пользователю предлагается вводить номер с использованием маски ввода. Преимущество: наглядное отображение номера сводит к минимуму возможные ошибки в номере. Недостаток: в каждой стране принято своё написание и длина номера.
  • Пользователю предлагается отдельно выбирать страну и отдельно вводить оставшуюся часть номера; возможно с применением маски ввода. Преимущество: возможность использования разных масок ввода для разных стран (а также регионов внутри страны). Недостатки: список стран (и регионов внутри каждой страны) может быть большим; номер телефона перестаёт существовать как единое целое (либо требуется предобработка перед сохранением и отображением номера).
  • Поставить знак + перед номером (за пределами input) и разрешить только ввод цифр. Преимущества: простота реализации. Недостаток: отсутствие наглядного отображения номера.
  • Предлагаемое решение В результате было решено доработать привычную маску ввода так, чтобы она менялась в соответствии с текущим значением номера. Кроме того, по мере ввода номера предлагается отображать название определившейся страны. Данный подход, субъективно, должен решить все недостатки перечисленных выше решений.

    С учётом того, что количество стран в мире относительно невелико, было принято решение составить список масок ввода для всех стран. В качестве источника использовались сведения , опубликованные на сайте международного союза электросвязи.

    Сбор данной информации преподнёс немало сюрпризов. В процессе сбора сведений приходилось учитывать все возможные варианты телефонных номеров, в том числе внутри страны. Однако, ввиду большого количества обработанной вручную информации, возможно, в собранной базе остались неточности. С течением времени планируется вносить исправления в первоначальный набор.

    Программная реализация В качестве ядра маски ввода была использована реализация jquery.inputmask , о которой многократно упоминалось на Хабрахабр. Данный плагин сейчас активно развивается и, к тому же, спроектирован таким образом, что для него достаточно просто писать расширения. Однако в данной задаче написать такое расширение оказалось практически невозможно. Я не стал дорабатывать или переписывать исходный плагин под свои нужды, т.к. его автор продолжает активную работу над расширением функционала, в результате чего применение моих правок может оказаться проблематичным. Поэтому мне пришлось написать плагин-надстройку над основным ядром, который отслеживает (плюс перехватывает) внешние воздействия и производит модификацию данных. Для того, чтобы внедрить свои обработчики внешних воздействий до обработчиков основного плагина использовался плагина-библиотека jquery.bind-first .Сортировка разрешённых масок ввода Для корректного выбора наиболее подходящей маски ввода весь набор масок требуется предварительно отсортировать специальным образом. При разработке правил сортировки были приняты следующие условности:
  • Все символы в маске ввода разделены на 2 типа: значимые символы (в моём случае это символ # , означающий произвольную цифру, и цифры 0-9) и символы-декораторы (все остальные).
  • Другое деление символов в маске ввода - это шаблонные символы (в моём случае это символ #) и все остальные.
  • В результате получились следующие правила сортировки в порядке их применения:

  • При посимвольном сравнении 2 масок ввода во внимание принимаются только значимые символы (не декораторы).
  • Разные шаблонные символы воспринимаются как равные, а остальные значимые символы сравниваются на основе их кода.
  • Нешаблонные символы всегда меньше шаблонных и в результате располагаются выше.
  • Чем короче длина значимых символов в маске ввода, тем маска ввода считается меньше и располагается выше.
  • Поиск подходящей маски ввода При сравнении входного текста с очередной маской из отсортированного списка принимаются во внимание только значимые символы каждой маски. Если строка оказывается длиннее маски ввода, несмотря на то что все предшествующие символы прошли проверку, данная маска ввода считается неподходящей. В случае, если входному тексту удовлетворяет несколько масок ввода, то возвращается первая из них. Далее в найденной маске все значимые символы (в том числе нешаблонные) заменяются на шаблонный, который является комбинацией всех символов, разрешённых любым из шаблонных символов.Обработка и перехват событий С целью предотвращения конфликтов с обработчиками событий основного ядра маски ввода перехватываются следующие события:
    • keydown - отслеживаются нажатия клавиш Backspace и Delete - с целью изменения текущей маски ввода перед тем как основной обработчик удалит один символ из текста. Кроме того, отслеживается нажатие клавиши Insert, которая изменяет режим ввода текста, для синхронизации.
    • keypress - поскольку вводимый символ может быть неразрешён оригинальной маской ввода (т.к. все значимые символы в ней заменены на шаблонный), требуется проверить новую строку на удовлетворение одной из разрешённых масок. В случае, если таких масок нет, то ввод символа отбрасывается, иначе - производится обновление маски ввода, после чего событие передаётся обработчику ядра.
    • paste , input - вставка текста из буфера обмена. Перед передачей обработки ядру производится подбор маски ввода для строки, получившейся в результате вставки текста из буфера обмена. В случае, если маску ввода подобрать не удалось, производится посимвольное урезание текста с конца - до тех пор, пока текст не станет удовлетворять хотя бы одной маске ввода. Аналогичная операция производится при исправлении текста в поле ввода вызовом функции val(), а также при инициализации маски ввода, если она применяется к непустому полю ввода.
    • dragdrop , drop - обработка аналогична событию paste.
    • 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 - регулярное выражение, описывающее значимые символы (в моём случае это /|#/);
    • key - имя параметра объекта массива, содержащего маску ввода.

    При подключении плагину передаётся специальный объект, описывающий его работу. Данный объект содержит следующий набор параметров:

    • inputmask - объект, содержащий параметры, передаваемые основному плагину inputmask;
    • match - регулярное выражение, описывающее значимые символы, за исключением шаблонных;
    • replace - шаблонный символ, на который будут заменены все значимые символы; может отсутствовать в объекте definitions объекта inputmask;
    • list - массив объектов, описывающих маски ввода;
    • listKey - имя параметра внутри объекта, хранящего маску ввода;
    • onMaskChange - функция, которая вызывается при обновлении маски ввода; в качестве первого параметра передаётся объект из массива, маска ввода которого соответствует введённому тексту, а в качестве второго - точность определения маски: true - маска ввода соответствует полностью, false - для достоверного определения маски требуется ввод дополнительных символов.

    Для инициализации плагина нужно применить метод inputmasks к полю ввода:
    $.fn.inputmasks = function(maskOpts, mode)

    • maskOpts - объект, описывающий работу плагина;
    • mode - необязательный; в настоящий момент поддерживается значение isCompleted - в результате метод возвращает true , если текст, соответствующей подходящей маске, введён полностью и false в противном случае.
    Пример подключения плагина
    Маска ввода var maskList = $.masksSort($.masksLoad("phone-codes.json"), ["#"], /|#/, "mask"); var maskOpts = { inputmask: { definitions: { "#": { validator: "", cardinality: 1 } }, //clearIncomplete: true, showMaskOnHover: false, autoUnmask: true }, match: //, 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(); Демонстрация Пример демонстрации разработанного плагина представлен на

    На первый взгляд, ответ очевиден: пометить поле «номер телефона» как обязательное для заполнения. Но есть ниши, в которых пользователь может уйти с сайта из-за лишних обязательных полей. Например, приложения, софт, сайты по продаже контента. Впрочем, номера пользователей для подобных проектов важны как дополнительные данные, которые дают возможность взаимодействовать с потенциальными клиентами в будущем. Тем более, что существует простое и эффективное решение — использование маски ввода. Докажем это кейсами.

    Зачем нужна маска ввода?

    Маска ввода показывает, в каком формате нужно вводить данные в поле. Например, если пользователь вводит номер телефона без кода города или телефон в поле для адреса, ему не удастся перейти к следующему пункту. Маска в формах обеспечивает единообразный вид вводимых данных, что упрощает поиск и управление базой. В рекомендациях Netpeak маска ввода телефонного номера — обязательный элемент формы заказа на сайте. Как и любая практическая рекомендация наших специалистов, это положение основано на успешных кейсах клиентов.

    Так как сайт специализировался на приложениях, поле для ввода номера на сайте было необязательным. Для отслеживания изменения процента клиентов, заполняющих поле «телефон» в форме заказа на сайте, мы применили пользовательскую переменную в Google Analytics. В феврале поле «телефон» не заполнил ни один из девяти покупателей. В марте мы внедрили маску ввода, и пользователи начали её заполнять. Для чистоты эксперимента поле оставили необязательным для заполнения и никаких других изменений не проводили.
    Результат за март — 19 номеров при 22 заполнивших заявку пользователей. Другими словами, 85% пользователей, заказавших приложение, оставили свой номер телефона.

    Кейс сайта информационного центра: увеличение количества заполнений поля телефонного номера на 15,4%

    Сайт клиента занимается услугами по написанию рефератов, курсовых, дипломных и прочих работ. Номер телефона пользователя желателен для связи, но на сайте это поле было необязательным. Пользователь мог не заполнять форму или написать что угодно в данном поле. Как и в первый раз, на первом этапе мы установили отслеживание заполнения поля «телефон» в Google Analytics. В ноябре из 59 заявок, оставленных посетителями сайта, 15 не содержали номеров. То есть компания получила лишь 74,6% отправленных форм с заполненным номером. Затем мы добавили маску ввода в поле для телефона. В декабре сайт получил 60 заявок. При этом только 6 заполненных форм не содержали телефона клиента. Следовательно, 90% отправленных форм заказа содержали правильно заполненное поле «телефон». За месяц — рост на 15,4%, только благодаря внедрению маски ввода номера. Напоследок — внутренний кейс агентства.

    Поле для номеров в форме заказа на сайте Netpeak также является необязательным. Но номера телефонов важны, чтобы клиенты всегда знали номер и статус своей заявки (мы высылаем эти данные по SMS), а также для оптимизации работы аккаунт-менеджеров. Период эксперимента, как и в прошлых примерах — два месяца. В итоге появления маски ввода номера, процент заполнений форм вырос с 44% до 83% — на 39,4%.
    После эксперимента мы внедрили маску на сайте. Поле для ввода номера осталось необязательным. Заявка не пройдет, только если в этом поле введен некорректный номер. При этом первые цифры в маске меняются в зависимости от страны, в которой находится пользователь сайта. Если речь идет о форме предварительного заказа, то интересно знать, насколько качественнее заявки с номерами телефонов. Мы взяли все заявки, когда-либо полученные через форму предзаказа и вычислили процент тех, что конвертировались в клиентов без номера и с ним. Последних оказалось больше всего на 0,81%.

    Вывод : если человек оставляет вам свой номер в форме, это еще не гарантия перечисления средств.

    Если говорить о форме предзаказа, на первый план выходят возможности по реактивации клиентов, возможности, которые открываются перед маркетологами, вооруженными базой личных телефонных номеров пользователей. Мы расскажем об успешных кейсах реактивации в одном из новых постов. А пока советуем почитать о мерах, которые стоит предпринять перед любыми действиями с телефонными номерами в базе. Делитесь в комментариях своим опытом внедрения маски ввода для телефонных номеров и наблюдениями за качеством пришедших заявок.