Обработка DOM-событий

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

Привязка событий к элементам

В Slim.js события привязываются через атрибуты в шаблоне компонента. Используется синтаксис @событие="метод". Например:

class ButtonComponent extends Slim {
  constructor() {
    super();
    this.count = 0;
  }

  increment() {
    this.count++;
  }

  get template() {
    return `
      <button @click="increment">Нажато {{count}} раз</button>
    `;
  }
}

customElements.define('button-component', ButtonComponent);

В этом примере @click="increment" автоматически регистрирует обработчик события click на кнопке, вызывая метод increment класса компонента. Важно, что Slim.js сохраняет контекст this, поэтому метод может напрямую обращаться к свойствам компонента.

События ввода и двухсторонняя привязка

Для работы с формами и полями ввода Slim.js предоставляет возможность связывать значения напрямую с состоянием компонента:

class InputComponent extends Slim {
  constructor() {
    super();
    this.name = '';
  }

  get template() {
    return `
      <input type="text" @input="name = $event.target.value">
      <p>Привет, {{name}}</p>
    `;
  }
}

customElements.define('input-component', InputComponent);

Событие input обновляет свойство name в реальном времени. $event — объект стандартного DOM-события, доступный в шаблоне для получения текущих значений.

Обработка пользовательских событий

Slim.js поддерживает создание и обработку пользовательских событий через метод dispatchEvent:

class ChildComponent extends Slim {
  notifyParent() {
    this.dispatchEvent(new CustomEvent('child-click', {
      detail: { message: 'Привет от дочернего компонента' },
      bubbles: true
    }));
  }

  get template() {
    return `<button @click="notifyParent">Сообщить родителю</button>`;
  }
}

customElements.define('child-component', ChildComponent);

class ParentComponent extends Slim {
  handleChildClick(event) {
    console.log(event.detail.message);
  }

  get template() {
    return `<child-component @child-click="handleChildClick"></child-component>`;
  }
}

customElements.define('parent-component', ParentComponent);

События можно передавать через иерархию компонентов благодаря параметру bubbles: true. Это упрощает коммуникацию между компонентами без использования глобального состояния.

Отмена стандартного поведения и остановка распространения

Slim.js позволяет использовать стандартные методы DOM-событий, такие как preventDefault и stopPropagation, прямо в шаблоне:

get template() {
  return `<a href="https://example.com" @click="$event.preventDefault(); doSomething()">Ссылка</a>`;
}

Здесь клик по ссылке не приведет к переходу на другую страницу, а вызовет метод doSomething компонента. $event обеспечивает доступ ко всем стандартным методам события.

События жизненного цикла компонента

Помимо DOM-событий, Slim.js предоставляет хуки для работы с жизненным циклом:

  • onBeforeCreated() — вызывается перед созданием компонента;
  • onAfterCreated() — после полной инициализации;
  • onBeforeUpdate() — перед обновлением DOM;
  • onAfterUpdate() — после обновления DOM;
  • onBeforeDestroy() — перед удалением компонента.

Эти хуки полезны для регистрации или снятия слушателей событий, чтобы избежать утечек памяти:

class TimerComponent extends Slim {
  onAfterCreated() {
    this.timer = setInterval(() => console.log('tick'), 1000);
  }

  onBeforeDestroy() {
    clearInterval(this.timer);
  }

  get template() {
    return `<p>Таймер работает</p>`;
  }
}

customElements.define('timer-component', TimerComponent);

Делегирование событий

Slim.js поддерживает делегирование через стандартный JavaScript-подход. Это полезно, если элементы создаются динамически:

get template() {
  return `
    <ul>
      <li @click="handleItemClick" each="item in items">{{item}}</li>
    </ul>
  `;
}

handleItemClick(event) {
  console.log('Нажат элемент:', event.target.textContent);
}

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

Обработка асинхронных событий

Методы, привязанные к событиям, могут быть асинхронными, что позволяет работать с API и таймерами без блокировки интерфейса:

async fetchData() {
  const response = await fetch('https://api.example.com/data');
  this.data = await response.json();
}

Асинхронный метод можно привязать напрямую:

<button @click="fetchData">Загрузить данные</button>

Slim.js корректно обработает промис и обновит привязанные значения после завершения операции.

Итоговая структура событий в Slim.js

  • Привязка событий: через @event="method".
  • Доступ к объекту события: $event.
  • Пользовательские события: dispatchEvent(new CustomEvent(...)).
  • Жизненный цикл компонентов: хуки для управления слушателями.
  • Асинхронная обработка: методы могут быть async.
  • Делегирование: уменьшает нагрузку на DOM при динамических элементах.

Slim.js обеспечивает лаконичное и эффективное управление событиями, сохраняя контекст компонента и минимизируя ручное вмешательство в DOM.