Отслеживание изменений в реальном времени

В основе механизма отслеживания изменений в Cleave.js лежит реактивная модель обработки ввода, при которой любое изменение значения в поле немедленно перехватывается, преобразуется и синхронизируется с внутренним состоянием экземпляра. Библиотека не опирается на сторонние state-менеджеры и не требует внешнего контроля формы — все изменения обрабатываются внутри экземпляра через событийный слой и перезапись DOM-значения.

Ключевой принцип заключается в разделении двух представлений данных:

  • raw value — «сырое» значение без форматирования
  • formatted value — отображаемое значение с масками, разделителями и правилами форматирования

Каждое изменение проходит полный цикл преобразования: ввод → нормализация → форматирование → синхронизация состояния → событие обновления.


Основной механизм перехвата изменений

Cleave.js привязывается к input-элементу и отслеживает изменения через события input, keydown, cut, paste и change. Однако основным триггером является именно input, так как он обеспечивает унифицированный поток изменений независимо от источника ввода (клавиатура, вставка, автозаполнение).

После каждого события выполняется пересчёт значения:

  1. Получение текущего значения из DOM
  2. Очистка от невалидных символов (по маске)
  3. Применение форматтера (номер карты, дата, телефон и т.д.)
  4. Обновление DOM значения
  5. Синхронизация внутреннего состояния
  6. Вызов callback-обработчиков

Callback onValueChanged

Центральным инструментом отслеживания изменений является onValueChanged. Он вызывается после каждого пересчёта значения и предоставляет доступ к текущему состоянию экземпляра.

Структура callback

Callback получает объект состояния:

  • value — текущее отформатированное значение
  • rawValue — значение без форматирования
  • previous — предыдущее состояние
  • type — тип изменения (insert, delete, init)
  • target — ссылка на input-элемент

Логика вызова

Callback срабатывает синхронно после завершения внутренней обработки. Это означает, что к моменту вызова DOM уже обновлён, а внутренние буферы синхронизированы.


Типы изменений и их классификация

Cleave.js различает несколько типов операций, что позволяет точно отслеживать поведение пользователя.

Insert

Возникает при добавлении символов. Включает:

  • ввод с клавиатуры
  • вставку из буфера обмена
  • автозаполнение браузера

В этом режиме система анализирует позицию каретки и корректирует её после форматирования.


Delete

Срабатывает при удалении символов. Особенность заключается в том, что Cleave.js пытается сохранить логическую целостность маски, даже если пользователь удаляет форматирующие символы (например, пробелы или дефисы).


Init

Инициализационный тип изменения возникает при создании экземпляра. Используется для первичной нормализации уже существующего значения в input.


Реальное время и синхронизация состояния

Отслеживание в реальном времени реализовано через немедленную синхронизацию состояния без промежуточного буфера. Это означает, что любое изменение сразу отражается в:

  • DOM-значении
  • внутреннем raw state
  • callback-данных

Такая модель исключает необходимость debounce по умолчанию, однако допускает внешнюю оптимизацию.


Управление значением через API

setRawValue

Метод setRawValue позволяет программно изменить значение без необходимости симулировать пользовательский ввод.

После вызова происходит полный цикл обработки:

  • установка raw значения
  • форматирование
  • обновление DOM
  • вызов onValueChanged

Особенность заключается в том, что изменение считается «искусственным», но обрабатывается тем же пайплайном, что и пользовательский ввод.


getRawValue и getFormattedValue

Для синхронизации внешнего состояния используются методы чтения:

  • getRawValue — возвращает чистое значение
  • getFormattedValue — возвращает отображаемую строку

Эти методы используются в реактивных сценариях, где необходимо отделить бизнес-логику от UI-форматирования.


Проблема бесконечных циклов обновления

При интеграции с фреймворками возникает риск зацикливания:

  1. изменение input → onValueChanged
  2. обновление state во внешней системе
  3. перерендер компонента
  4. повторное применение значения через setValue

Cleave.js не содержит встроенной защиты от таких циклов, поэтому контроль осуществляется на уровне приложения через сравнение значений:

  • проверка rawValue перед обновлением
  • сравнение предыдущего состояния
  • игнорирование повторных одинаковых значений

Реализация throttling и debounce

Хотя библиотека не ограничивает частоту вызовов onValueChanged, в высоконагруженных сценариях применяется внешняя оптимизация.

Throttle

Используется для сокращения частоты обновлений при быстром вводе:

  • каждое N-е изменение проходит в callback
  • промежуточные состояния игнорируются

Debounce

Применяется для обработки финального состояния после паузы ввода:

  • обновление происходит после остановки ввода
  • полезно для отправки данных на сервер

Cleave.js при этом продолжает обновлять DOM в реальном времени, даже если внешняя логика ограничена.


Отслеживание каретки при изменениях

Одной из сложных задач является корректировка позиции курсора после форматирования. При каждом изменении Cleave.js:

  1. фиксирует текущую позицию каретки
  2. выполняет форматирование строки
  3. вычисляет смещение из-за добавленных символов
  4. восстанавливает логическую позицию

Это особенно важно при:

  • вставке разделителей (пробелы, дефисы)
  • изменении длины строки
  • применении масок кредитных карт

Работа с масками и динамическими форматами

При использовании динамических масок (например, определение типа карты или телефона) система пересчитывает правила форматирования при каждом вводе.

Это означает, что:

  • структура маски может изменяться на лету
  • onValueChanged может отражать смену типа формата
  • raw value остаётся стабильным источником истины

Интеграция с внешними состояниями

При подключении к внешним моделям данных (Redux, MobX, Vue reactive, React state) ключевым становится принцип однонаправленного потока данных:

  • Cleave.js управляет DOM
  • внешняя система управляет значением через setRawValue
  • синхронизация происходит через onValueChanged

Любая попытка двустороннего биндинга без фильтрации приводит к повторным перерендерам и деградации производительности.


Особенности поведения при вставке больших данных

При вставке больших строк (например, номер карты из менеджера паролей) происходит пакетная обработка:

  • мгновенная нормализация всей строки
  • однократное форматирование
  • один вызов onValueChanged

Это отличается от посимвольного ввода, где событие вызывается на каждом шаге.


Оптимизационные механизмы

Внутри механизма отслеживания изменений используются несколько оптимизаций:

  • минимизация перезаписи DOM (изменение только при отличии значения)
  • кеширование результата форматирования
  • пропуск повторной обработки идентичного raw value
  • быстрые проверки регулярных выражений для масок

Эти меры позволяют сохранять стабильную работу даже при частых изменениях ввода.


Поведение в нестандартных сценариях ввода

Автозаполнение браузера

Срабатывает как единичное событие вставки, после чего выполняется полный цикл форматирования.

Drag-and-drop вставка

Обрабатывается как paste-событие с последующей нормализацией.

IME ввод (азиатские языки)

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


Модель событийного потока

Внутренний поток можно описать как последовательность:

DOM input event → preprocessing → value normalization → formatting engine → DOM update → state sync → onValueChanged callback

Каждый этап строго синхронный, что обеспечивает предсказуемость поведения и отсутствие расхождений между DOM и внутренним состоянием.