Вы когда-нибудь задумывались, как реализовать плавный UX-поток, который можно найти в большинстве форм кредитных карт? Вы задавались вопросом, как разделить номер кредитной карты на группы по четыре, дату истечения срока действия в формате «ММ/ГГ» в поле ввода и т. д.?
Ну, я тоже не знал, пока мне не пришлось реализовать это в первый раз. 😅
Как всегда, нет необходимости изобретать велосипед, и есть множество хороших библиотек, которые решают эту проблему, если вы делаете свое собственное приложение/хобби-проект. Большинство из них подойдет. Но если вы реализуете чужой дизайн, вам часто будет сложно идеально вписать эти готовые решения в существующую систему.
Мы пойдем по среднему пути: воспользуемся карточными утилитами Эрика Расмуссена (известного эксперта по формам) и добавим пару дополнительных функций, чтобы все это идеально сочеталось с остальной частью нашего пользовательского интерфейса.
Итак, давайте начнем с форматирования номера кредитной карты.
export function formatCreditCardNumber(value: string) { if (!value) { return value; } const clearValue = clearNumber(value); let nextValue; nextValue = `${clearValue.slice(0, 4)} ${clearValue.slice( 4, 8 )} ${clearValue.slice(8, 12)} ${clearValue.slice(12, 19)}`; return nextValue.trim(); } function clearNumber(value = '') { return value.replace(/\D+/g, ''); }
Мы используем такую функцию:
{({ touched, errors, setFieldValue }) => { return ( <Form className={`${ className ? className : '' } flex flex-col space-y-4 text-black lg:space-y-6`} > <FieldInput maxLength={20} name="cardNumber" type="text" inputMode="numeric" placeholder="0000 0000 0000 0000" label={t('dashboard:account.cards.card-number')} id="cardNumber" onKeyPress={event => { checkIsNumber(event); }} onChange={event => { const formatted = (isNaN( Number( event.target.value.replace( /\s/g, '' ) ) ) && // edge-case of c/p-ing strings into cc number field '0') || formatCreditCardNumber( event.target.value ); setFieldValue('cardNumber', formatted); }} // ... />
Зоркий глаз заметит несколько вещей:
const checkIsNumber = (e: React.KeyboardEvent<HTMLInputElement>) => { const pattern = /^[0-9]$/; if (!pattern.test(e.key)) { e.preventDefault(); e.stopPropagation(); return false; } return true; };
Эрик элегантно решил эту проблему с помощью атрибута шаблона во входном теге.
pattern="[\d| ]{16,22}"
Вы простите JavaScript-программисту за то, что он в очередной раз подтвердил поговорку: «Для человека с молотком все выглядит как гвоздь» 😅
Наконец, мы форматируем дату истечения срока действия с помощью
export function formatExpirationDate(value: string) { const clearValue = clearNumber(value); if (clearValue.length >= 3) { return `${ +clearValue.slice(0, 2) > 12 ? 12 : clearValue.slice(0, 2) }/${clearValue.slice(2, 4)}`; } return clearValue || ''; }
Для достижения конечного результата:
Вот и все, народ! Если вы хотите узнать о некоторых незначительных улучшениях в этом коде и нюансах — свяжитесь со мной и дайте мне знать!
Первоначально опубликовано на https://locastic.com 6 октября 2022 г.