Как сделать маску для текстовых полей input

Частая задача при вёрстке макетов - добавление масок для текстовых полей, чтобы пользователь вводил данные именно в том формате, который необходим

В данной статье для добавления масок будем использовать плагин imask.js

1



Прежде чем начать, хотел бы обратить внимание, что у блога есть телеграм канал https://t.me/frontips, где можно узнавать о выходе новых статей и со временем будет появляться больше интересной и полезной информации.

Поддержите развитие блога и канала подпиской!

А теперь перейдём к теме статьи ;) Приятного чтения!



Создаём структуру

Для начала структура будет содержать одно поле ввода <input type="text"/>

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <title>Input Mask</title>
    <link rel="stylesheet" href="css/bootstrap-reboot.min.css"/>
  </head>
  <body>
    <div class="wrapper">
      <div class="wrapper__input">
        <input type="text"/> <!-- единственное поле ввода -->
      </div>
    </div>
    <script src="js/main.js"></script>
  </body>
</html>


Добавим стилей

Напишем немного стилей для более приятного восприятия

.wrapper {
  display: flex;
  padding: 64px 0;
  flex-direction: column;
  align-items: center;
}
.wrapper__input {
  max-width: 440px;
  width: 100%;
}
.wrapper__input:not(:last-child) {
  margin-bottom: 16px;
}
.wrapper__input input {
  width: 100%;
  height: 48px;
  border: 2px solid #3626a7;
  background: rgba(54,38,167,0.32);
  border-radius: 8px;
  text-align: center;
  color: #fff;
  font-size: 24px;
}
.wrapper__input input:focus {
  outline: none;
  background: rgba(54,38,167,0.64);
}


Получаем стандартное поле ввода без маски




Подключаем плагин imask.js

Плагин imask.js можно подключить через CDN

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <title>Input Mask</title>
    <link rel="stylesheet" href="css/bootstrap-reboot.min.css"/>
  </head>
  <body>
    <div class="wrapper">
      <div class="wrapper__input">
        <input type="text"/>
      </div>
    </div>
    <script src="https://unpkg.com/imask"></script> <!-- Подключаем плагин через CDN -->
    <script src="js/main.js"></script>
  </body>
</html>


или локально

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <title>Input Mask</title>
    <link rel="stylesheet" href="css/bootstrap-reboot.min.css"/>
  </head>
  <body>
    <div class="wrapper">
      <div class="wrapper__input">
        <input type="text"/>
      </div>
    </div>
    <script src="js/imask.js"></script> <!-- Подключаем плагин локально -->
    <script src="js/main.js"></script>
  </body>
</html>

Чтобы скачать последнюю версию плагина imask.js, просто берем адрес из подключения через CDN (https://unpkg.com/imask), вставляем в адресную строку браузера и сохраняем файл к себе в проект



Базовое использование плагина imask.js

Сделаем маску для ввода номера телефона

document.addEventListener('DOMContentLoaded', () => {

  const inputElement = document.querySelector('input') // ищем наш единственный input
  const maskOptions = { // создаем объект параметров
    mask: '+{7}(000)000-00-00' // задаем единственный параметр mask
  }
  IMask(inputElement, maskOptions) // запускаем плагин с переданными параметрами

})


Получаем следующий результат (попробуйте ввести любые цифры)



Несколько полей ввода с одинаковой маской

Чаще всего, однотипных полей ввода несколько. Чтобы определить однотипные поля ввода, будем добавлять им data-атрибут.

Например, для полей с маской номера телефона добавим <input type="text" data-mask="phone"/>

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <title>Input Mask</title>
    <link rel="stylesheet" href="css/bootstrap-reboot.min.css"/>
  </head>
  <body>
    <div class="wrapper">
      <div class="wrapper__input">
        <input type="text" data-mask="phone"/> <!-- добавляем data-mask="phone" -->
      </div>
      <div class="wrapper__input">
        <input type="text" data-mask="phone"/> <!-- добавляем data-mask="phone" -->
      </div>
    </div>
    <script src="js/imask.js"></script>
    <script src="js/main.js"></script>
  </body>
</html>


Далее, чтобы маска для ввода номера телефона применилась ко всем необходимым полям, пишем следующий код

document.addEventListener('DOMContentLoaded', () => {

  const elements = document.querySelectorAll('[data-mask="phone"]') // ищем все поля с атрибутом data-mask="phone"
  if (!elements) return // если таких нет, прекращаем выполнение функции
  const phoneOptions = { // создаем объект параметров
    mask: '+{7}(000)000-00-00' // задаем единственный параметр mask
  }
  elements.forEach(el => { // для каждого найденного поля с атрибутом [data-mask="phone"]
    IMask(el, phoneOptions) // инициализируем плагин с установленными выше параметрами
  })

})


Теперь маска будет работать на всех необходимых полях



Сделаем более универсальную функцию

Добавим в структуру несколько других типов масок

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <title>Input Mask</title>
    <link rel="stylesheet" href="css/bootstrap-reboot.min.css"/>
  </head>
  <body>
    <div class="wrapper">
      <div class="wrapper__input">
        <input type="text" data-mask="phone"/> <!-- поле ввода для номера телефона -->
      </div>
      <div class="wrapper__input">
        <input type="text" data-mask="postalCode"/> <!-- поле ввода для почтового индекса -->
      </div>
      <div class="wrapper__input">
        <input type="text" data-mask="date"/> <!-- поле ввода для даты -->
      </div>
      <div class="wrapper__input">
        <input type="text" data-mask="number"/> <!-- поле ввода для числа -->
      </div>
    </div>
    <script src="js/imask.js"></script>
    <script src="js/main.js"></script>
  </body>
</html>


Чтобы не повторять один и тот же код для каждой маски, сделаем более универсальную функцию, которая будет принимать значение data-атрибута поля ввода input и объект параметров маски

document.addEventListener('DOMContentLoaded', () => {

  const mask = (dataValue, options) => { // создаем универсальную функцию
    const elements = document.querySelectorAll(`[data-mask="${dataValue}"]`) // ищем поля ввода по селектору с переданным значением data-атрибута
    if (!elements) return // если таких полей ввода нет, прерываем функцию

    elements.forEach(el => { // для каждого из полей ввода
      IMask(el, options) // инициализируем плагин imask для необходимых полей ввода с переданными параметрами маски
    })
  }

  // Используем наше функцию mask для разных типов масок

  // Маска для номера телефона
  mask('phone', {
    mask: '+{7}(000)000-00-00'
  })

  // Маска для почтового индекса
  mask('postalCode', {
    mask: '000000' // шесть цифр
  })

  // Маска для даты
  mask('date', {
    mask: Date,
    min: new Date(1900, 0, 1), // минимальная дата 01.01.1900
  })

  // Маска для числа
  mask('number', {
    mask: Number,
    thousandsSeparator: ' ' // разделитель тысяч в числе
  })

})


Получаем следующий результат

Больше примеров и документация на официальном сайта плагина - https://imask.js.org/



Добавим немного эффектов :)

Этот раздел уже не относится к плагину imask.js и маске ввода

Просто, для разнообразия, добавим немного эффектов при вводе текста в поле input

Возьмем следующую структуру

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <title>Input Mask</title>
    <link rel="stylesheet" href="css/bootstrap-reboot.min.css"/>
  </head>
  <body>
    <div class="wrapper">
      <div class="wrapper__input">
        <input type="text" data-mask="phone"/>
      </div>
    </div>
    <script src="js/imask.js"></script>
    <script src="js/main.js"></script>
  </body>
</html>


Добавим немного стилей для анимации

body {
  background: #fff;
}
.wrapper {
  display: flex;
  padding: 64px 0;
  flex-direction: column;
  align-items: center;
}
.wrapper__input {
  max-width: 440px;
  width: 100%;
}
.wrapper__input:not(:last-child) {
  margin-bottom: 16px;
}
.wrapper__input input {
  width: 100%;
  height: 48px;
  border: 2px solid #3626a7;
  background: rgba(54,38,167,0.32);
  border-radius: 8px;
  text-align: center;
  color: #fff;
  font-size: 24px;
  transition: 0.25s;
  transform: scaleX(1) scaleY(1);
}
.wrapper__input input:focus {
  outline: none;
  background: rgba(54,38,167,0.64);
}

/* Класс для запуска анимации */
.wrapper__input_animate {
  -webkit-animation: shake 0.2s ease-out;
  animation: shake 0.2s ease-out;
}

/* Анимация */
@-webkit-keyframes shake {
  0% {
    transform: scaleX(1) scaleY(1);
  }
  20% {
    transform: scaleX(1.1) scaleY(0.8);
  }
  100% {
    transform: scaleX(1);
  }
}
@keyframes shake {
  0% {
    transform: scaleX(1) scaleY(1);
  }
  20% {
    transform: scaleX(1.1) scaleY(0.8);
  }
  100% {
    transform: scaleX(1);
  }
}


Напишем логику

document.addEventListener('DOMContentLoaded', () => {

  const mask = (dataValue, options) => {
    const elements = document.querySelectorAll(`[data-mask="${dataValue}"]`)
    if (!elements) return
    elements.forEach(el => {
      IMask(el, options)
    })
  }

  mask('phone', {
    mask: '+{7}(000)000-00-00'
  })

  const inputs = document.querySelectorAll('.wrapper__input') // находим необходимые элементы
  if (!inputs) return // если нет таких элементов, прерываем выполнение функции
  inputs.forEach(el => { // для каждого из них
    const input = el.querySelector('input') // находим дочерний input
    if (!input) return // если дочернего input нет, прерываем функцию
    let locked = false // объявляем переменную которая будет блокировать лишние вызовы при наборе текста
    input.addEventListener('input', () => { // при вводе текста в input
      if (locked) return // если возможность вызова функции при вводе текста не заблокирована
      locked = true // то временно блокируем ее
      el.classList.add('wrapper__input_animate') // добавляем класс анимации
      setTimeout(() => { // и через указанное время
        el.classList.remove('wrapper__input_animate') // удаляем класс анимации
        locked = false // разблокируем возможность вызова функции при вводе текста
      }, 200) // время ожидания 200 миллисекунд = время анимации
    })
  })
})


Получаем следующий результат (попробуйте ввести любые цифры)



Итоги

Постарался рассказать базовую логику добавления масок для текстовых полей, используя один из многих доступных плагинов

Надеюсь, на основе этих базовых знаний, вы сможете добавлять и более гибко настраивать маски в зависимости от задачи

Буду рад, если статья оказалась полезной

Спасибо за ваше внимание и уделённое время!



Друзья, стараюсь для вас, поддержите проект!

Подписывайтесь, впереди много всего интересного и полезного ;)

Telegram - https://t.me/frontips

VK - https://vk.com/frontips