К содержанию

Навигация

События

Глава описывает, какие события отправляет компонент и по каким правилам. Единые правила позволяют проекту подписываться на любой компонент одинаково.

Событие сообщает, что произошло, и передаёт данные в event.detail. Компоненту не нужно знать, какая страница его использует: проект подписывается на событие и решает, что делать дальше. Поэтому дочерний компонент не связывают с конкретным глобальным объектом проекта.

Три вида событий

Вид Имя Пример
Изменение значения change Выбрана дата, введён текст, переключён флажок
События компонента Своё у каждого компонента sf-popover-open, sf-page-change, sf-file-upload:select, modal:after-close, drawer:after-open, close
Этапы жизненного цикла sf-<этап> sf-connected, sf-after-render

У событий компонентов нет единого шаблона имени. Точное имя каждого события записано в разделе events манифеста компонента и на его странице в справочнике; имя не выводят по аналогии с другим компонентом.

В классе событие компонента обычно отправляется методом emitComponentEvent('table-query-intent', detail) — базовый класс сам добавляет префикс sf-: вызов emitComponentEvent('confirm') создаёт событие sf-confirm. Подписка использует полное имя.

detail частых событий:

Событие detail
change у sf-datepicker value (дата ГГГГ-ММ-ДД или пара [начало, конец] при range), date, isoValue, formattedValue (дата в формате format), range, format; при range ещё startValue, endValue, formattedStartValue, formattedEndValue, startIsoValue, endIsoValue
change у sf-dropdown value (значение выбранного варианта), label, values (все выбранные значения), item, root, multiple
sf-page-change у sf-pagination component, tagName, template, previous, current, total, pageCount, pageSize
sf-page-size-change у sf-pagination component, tagName, template, previous, pageSize, current, total, pageCount
modal:before-open, modal:after-open, modal:after-close и другие modal:* component и modal (сам элемент <sf-modal>), modalId, root, phase
sf-theme-change на window theme, preference (см. Как выбирается тема на странице)

Остальные — на страницах компонентов в справочнике. У sf-datepicker прежнее имя sf-change несёт другой detail: все данные компонента, а не состав change; подписывайтесь на change.

Пример

Счётчик хранит значение, поэтому сообщает о его изменении событием change, как поля Framework. Класс отправляет его сам: this.dispatchEvent(new CustomEvent('change', { bubbles: true, composed: true, detail: { value } })). Страница подписывается через element.addEventListener('change', handler) и показывает данные события под примером.

HTML
<project-counter count="1"></project-counter>
<p id="counter-log" role="status">Нажмите кнопку: ниже появятся данные события.</p>
JavaScript
async function start() {
  if (typeof window.SF?.loadSmartBase !== 'function') {
    await new Promise((resolve, reject) => {
      const ready = () => { clearTimeout(timeout); resolve(); };
      const timeout = setTimeout(() => { window.removeEventListener('sf-loader-init', ready); reject(new Error('Loader не запустился')); }, 15000);
      window.addEventListener('sf-loader-init', ready, { once: true });
    });
  }
  await SF.loadSmartBase();
  const { SfBaseElement, html } = SF.smart;
  // The component's own words: English in `en`, Russian in `ru`.
  const TEXT = {
    en: { count: 'Count', add: 'Add' },
    ru: { count: 'Количество', add: 'Добавить' },
  };
  class ProjectCounter extends SfBaseElement {
    static get props() {
      // A label prop defaults to empty: the English word lives in the dictionary.
      return { count: { type: Number, default: 0 }, addLabel: { default: '' } };
    }
    templateContext() {
      // Keeps component, rootClass, rootStyle and every declared prop.
      return this.createPropsTemplateContext({
        countText: SF.pageText(TEXT, 'count', this),
        addText: this.getProp('addLabel') || SF.pageText(TEXT, 'add', this),
      });
    }
    increment() {
      const count = this.getProp('count') + 1;
      this.setAttribute('count', String(count));
      this.dispatchEvent(new CustomEvent('change', { bubbles: true, composed: true, detail: { value: count } }));
    }
    template() {
      const { count, countText, addText, rootClass } = this.templateContext();
      return html`<div class="flex gap-2 items-cross-center ${rootClass}">
        <output aria-live="polite">${countText}: ${count}</output>
        <button type="button"
                class="sf-button sf-button--outline sf-button--on-surface sf-button--size-1/2"
                @click=${() => this.increment()}>
          <span class="sf-button-text-container">${addText}</span>
        </button>
      </div>`;
    }
  }
  ProjectCounter.define('project-counter');
  document.querySelector('project-counter').addEventListener('change', event => {
    document.querySelector('#counter-log').textContent = JSON.stringify({ value: event.detail.value });
  });
}
start().catch(error => { document.querySelector('#counter-log').textContent = error.message; });

Соглашение change

  • Любой элемент формы сообщает подтверждённое изменение значения событием change на своём теге.
  • Ровно один раз на одно действие человека.
  • Непрерывное действие — удержание кнопки или клавиши (автоповтор), перетаскивание — одно действие: change отправляется один раз, когда оно завершилось (кнопку или клавишу отпустили). Промежуточные значения, если подписчику они нужны, сообщаются событием input, как у нативного <input type="range">. Его detail устроен так же, как у change того же компонента, и содержит по меньшей мере value (у sf-color оба события несут {value, name}). Для клавиши change уходит, когда её отпустили, — и после одиночного нажатия, и после автоповтора.
  • Значение, установленное из кода, — не изменение.
  • Если нативный элемент внутри уже отправил change, компонент не повторяет его — иначе подписчик получит два события.
  • Если компонент сам отправляет change со своим detail, событие change внутренних нативных полей он останавливает (event.stopPropagation()): иначе подписчик получит второе событие без detail.

Для совместимости компоненты продолжают отправлять и дополнительные имена события изменения; в манифесте они отмечены как alias_of: "change" (см. Жизненный цикл изменений).

Правила для события

  • События всплывают (bubbles, composed): родитель получает события вложенных элементов. Проверяйте event.target, если внутри несколько одинаковых контролов.
  • Не отправляйте то же событие повторно из каждого родителя — исходное и так всплывает.
  • В detail — минимальные сведения о действии. Не передавайте секреты и целый ответ сервера. Событие, отправленное через emitComponentEvent, получает от базового класса ещё component, tagName и template. Событие change и другие события, которые компонент отправляет сам через dispatchEvent, этих полей не содержат.
  • Копия содержимого сохраняет то, что не переносит JSON. JSON.parse(JSON.stringify(...)) молча превращает File, Blob, Date и Map в {} или строку. Например, намерение загрузки придёт с пустым объектом вместо файла, и проверка размера на стороне приложения пропустит всё. Копируйте простые части, а такие значения передавайте по ссылке или через structuredClone.
  • Слушатель на document или window компонент хранит как функцию и снимает при отключении (см. Освобождение ресурсов).
  • Каждое событие объявлено в разделе events манифеста; схема detail записана в его поле payload.

Смотрите также

Поиск по документации

Введите минимум 2 символа

    Настройки

    Тема
    Размер шрифта
    Ширина страницы