Обработка событий и связывание данных

Riot.js предоставляет простой и интуитивно понятный механизм работы с событиями. События связываются с методами компонента через атрибут on:<event> в шаблоне. Такой подход позволяет легко отделять логику интерфейса от структуры HTML.

<counter>
  <button oncl ick={increment}>Увеличить</button>
  <p>Значение: {count}</p>

  <script>
    export default {
      count: 0,
      increment() {
        this.count++
      }
    }
  </script>
</counter>

В этом примере метод increment вызывается при клике на кнопку. Важно, что this внутри метода ссылается на текущий экземпляр компонента, что обеспечивает прямой доступ к его состоянию и методам.


События пользовательских компонентов

Riot.js позволяет компонентам генерировать собственные события через метод this.$emit. Это полезно для передачи данных от дочернего компонента к родительскому без прямого доступа к его состоянию.

<child>
  <button oncl ick={notifyParent}>Отправить сообщение</button>

  <script>
    export default {
      notifyParent() {
        this.$emit('message', 'Привет от дочернего компонента')
      }
    }
  </script>
</child>

<parent>
  <child onmess age={handleMessage}></child>

  <script>
    export default {
      handleMessage(msg) {
        console.log(msg) // Выведет: Привет от дочернего компонента
      }
    }
  </script>
</parent>

Метод $emit принимает первым аргументом имя события, вторым — передаваемые данные. Родительский компонент может обрабатывать событие через атрибут on<event>.


Связывание данных

Riot.js поддерживает двустороннее связывание данных, что позволяет синхронизировать состояние компонента с элементами формы. Для этого используется директива bind.

<input type="text" bind={name}>
<p>Привет, {name}!</p>

<script>
  export default {
    name: ''
  }
</script>

Каждое изменение значения input автоматически обновляет свойство name, а изменение свойства в скрипте обновляет значение в поле ввода. Это упрощает работу с формами и состоянием компонентов.


Динамическое связывание событий

Riot.js позволяет динамически назначать обработчики с помощью выражений Jav * aScript:

<button oncl ick={count > 5 ? reset : increment}>
  {count > 5 ? 'Сбросить' : 'Увеличить'}
</button>

<p>Текущее значение: {count}</p>

<script>
  export default {
    count: 0,
    increment() { this.count++ },
    reset() { this.count = 0 }
  }
</script>

Здесь одно событие клика выполняет разные функции в зависимости от текущего состояния компонента. Такой подход делает компоненты более гибкими и адаптивными.


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

Riot.js предоставляет встроенные события жизненного цикла: mount, unmount, update. Они позволяют выполнять действия при создании, удалении или обновлении компонента.

<logger>
  <p>Проверка жизненного цикла</p>

  <script>
    export default {
      onMounted() {
        console.log('Компонент смонтирован')
      },
      onUpdated() {
        console.log('Компонент обновлён')
      },
      onUnmounted() {
        console.log('Компонент удалён')
      }
    }
  </script>
</logger>

Методы onMounted, onUpdated и onUnmounted вызываются автоматически и предоставляют доступ к DOM и состоянию компонента. Это удобно для интеграции с внешними библиотеками или выполнения побочных эффектов.


Комбинирование событий и данных

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

<todo-app>
  <input type="text" bind={newTask} placeholder="Добавить задачу">
  <button oncl ick={addTask}>Добавить</button>

  <ul>
    <li each={task, i in tasks}>
      {task} <button oncl ick={() => removeTask(i)}>Удалить</button>
    </li>
  </ul>

  <script>
    export default {
      newTask: '',
      tasks: [],
      addTask() {
        if(this.newTask.trim()) {
          this.tasks = [...this.tasks, this.newTask]
          this.newTask = ''
        }
      },
      removeTask(index) {
        this.tasks = this.tasks.filter((_, i) => i !== index)
      }
    }
  </script>
</todo-app>

Использование директивы each позволяет динамически рендерить элементы массива. Каждое событие клика на кнопку удаления запускает соответствующий метод с передачей индекса задачи. Состояние компонента автоматически синхронизируется с DOM.


Особенности работы с контекстом this

В Riot.js важно понимать контекст this при работе с методами. Если событие передаётся как callback внешней функции, необходимо корректно привязать this:

setTimeout(this.increment.bind(this), 1000)

Или использовать стрелочные функции, которые сохраняют контекст:

setTimeout(() => this.increment(), 1000)

Это предотвращает ошибки доступа к свойствам компонента при асинхронных операциях.


Итоговая структура эффективного компонента

  • Состояние: определяется в export default.
  • Шаблон: связывает элементы с данными через {} и директивы bind.
  • Обработчики событий: назначаются через on:<event> или $emit для передачи данных родителю.
  • Жизненный цикл: onMounted, onUpdated, onUnmounted для управления побочными эффектами.
  • Динамика: использование each, условных выражений и привязки методов позволяет строить интерактивные интерфейсы.

Эта структура обеспечивает прозрачность, лёгкость сопровождения и гибкость компонентов Riot.js.