Номер банковской карты (PAN — Primary Account Number) представляет собой последовательность цифр, которая кодирует тип платёжной системы, эмитента и уникальный идентификатор счёта. На практике длина PAN варьируется от 13 до 19 символов, однако наиболее распространённый формат — 16 цифр.
В интерфейсах ввода такие данные требуют строгого контроля формата: разделения на группы, ограничения допустимых символов, проверки префиксов и длины. Для этих задач используется библиотека Inputmask, позволяющая описывать правила ввода через маски и динамическую валидацию.
Типичная визуальная структура номера карты:
#### #### #### ######## ###### #####Маска выполняет несколько функций:
Простейшая реализация:
import Inputmask from "inputmask";
Inputmask("9999 9999 9999 9999").mask("#card");
Здесь:
9 — обязательная цифра;#card — целевой input-элемент.Такая маска подходит для фиксированных 16-значных номеров, но не учитывает различия между платёжными системами.
Для повышения гибкости применяется символ 9 или
\d-аналог через определения:
Inputmask({
mask: "9999 9999 9999 9999 999",
placeholder: "",
showMaskOnHover: false,
showMaskOnFocus: true
}).mask("#card");
Добавление 19 символов позволяет учитывать редкие форматы карт (например, некоторых локальных банковских систем).
Карточные номера не унифицированы. Например:
4-6-5)Для поддержки всех форматов применяется динамическая маска:
Inputmask({
mask: [
"9999 9999 9999 9999",
"9999 999999 99999"
],
keepStatic: true
}).mask("#card");
Параметр keepStatic: true позволяет библиотеке выбирать
подходящий шаблон в процессе ввода.
Первые 6–8 цифр PAN формируют BIN (Bank Identification Number), который определяет платёжную систему.
Пример логики определения:
function detectCardType(value) {
const cleaned = value.replace(/\s/g, "");
if (/^4/.test(cleaned)) return "visa";
if (/^5[1-5]/.test(cleaned)) return "mastercard";
if (/^3[47]/.test(cleaned)) return "amex";
return "unknown";
}
Эта логика используется совместно с Inputmask для переключения маски в реальном времени.
const amexMask = "9999 999999 99999";
const defaultMask = "9999 9999 9999 9999";
const mask = Inputmask({
mask: defaultMask,
onBeforeMask: function (value) {
return value.replace(/\D/g, "");
}
});
mask.mask("#card");
document.querySelector("#card").addEventListener("input", (e) => {
const value = e.target.value.replace(/\s/g, "");
if (/^3[47]/.test(value)) {
mask.option({ mask: amexMask });
} else {
mask.option({ mask: defaultMask });
}
});
Такой подход обеспечивает адаптивный ввод без перезагрузки компонента.
Одной из ключевых задач является визуальное разделение PAN на читаемые блоки.
Inputmask поддерживает статические и динамические разделители:
Inputmask({
mask: "9999 9999 9999 9999",
groupSeparator: " ",
autoGroup: true
}).mask("#card");
Параметр autoGroup позволяет автоматически вставлять
разделители по шаблону.
Банковские номера строго цифровые, поэтому необходимо исключить:
Реализация через definitions:
Inputmask({
mask: "9999 9999 9999 9999",
definitions: {
"9": {
validator: "[0-9]",
cardinality: 1
}
}
}).mask("#card");
Такой подход усиливает контроль над вводом и исключает некорректные символы на уровне библиотеки.
При вставке длинных строк часто поступают данные без пробелов:
Inputmask({
mask: "9999 9999 9999 9999",
onBeforePaste: function (pastedValue) {
return pastedValue.replace(/\D/g, "");
}
}).mask("#card");
Это обеспечивает нормализацию входных данных до применения маски.
Для банковских форм важно определять момент полного заполнения:
Inputmask({
mask: "9999 9999 9999 9999",
oncomplete: function () {
console.log("Номер карты введён полностью");
},
onincomplete: function () {
console.log("Ввод не завершён");
}
}).mask("#card");
Такие события используются для активации кнопки отправки формы.
Inputmask не выполняет финансовую валидацию, но может работать совместно с алгоритмом Луна:
function luhnCheck(value) {
const digits = value.replace(/\D/g, "").split("").reverse();
let sum = 0;
for (let i = 0; i < digits.length; i++) {
let n = parseInt(digits[i], 10);
if (i % 2 === 1) {
n *= 2;
if (n > 9) n -= 9;
}
sum += n;
}
return sum % 10 === 0;
}
Использование вместе с Inputmask:
document.querySelector("#card").addEventListener("blur", (e) => {
const valid = luhnCheck(e.target.value);
if (!valid) {
e.target.classList.add("error");
}
});
В современных SPA Inputmask часто применяется внутри компонентов:
import Inputmask from "inputmask";
function attachCardMask(el) {
const im = new Inputmask({
mask: "9999 9999 9999 9999",
placeholder: " "
});
im.mask(el);
return im;
}
При смене состояния компонента маска может переинициализироваться без потери данных.
При работе с банковскими данными критичны следующие параметры:
greedy: false — предотвращает избыточное
заполнение;clearIncomplete: true — очищает неполные значения;autoUnmask: true — возвращает «чистое» значение без
форматирования.Пример:
Inputmask({
mask: "9999 9999 9999 9999",
greedy: false,
clearIncomplete: true,
autoUnmask: true
}).mask("#card");
Маска не является средством безопасности, но снижает вероятность ошибок:
Комбинация маски и серверной проверки остаётся стандартной практикой при работе с PAN.