Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

События компонента: emit

Данные идут от родителя к дочернему компоненту через props, а сообщения в обратную сторону — через события. Дочерний компонент генерирует (emit) событие, например «задачу нужно удалить», а родитель слушает его через @ так же, как клик по кнопке, и сам меняет данные.

Объявление событий

Добавьте в src/components/TodoItem.vue макрос defineEmits со списком событий:

<!-- src/components/TodoItem.vue -->
<script setup>
defineProps({
  todo: { type: Object, required: true },
})
 
const emit = defineEmits(['remove'])
</script>
 
<template>
  <li>
    {{ todo.text }}
    <button @click="emit('remove')">Удалить</button>
  </li>
</template>

Клик по кнопке вызывает emit('remove') — компонент сообщает наружу, что пользователь хочет удалить задачу. Сам он ничего не удаляет.

Обработка в родителе

<!-- src/App.vue -->
<script setup>
import { ref } from 'vue'
import TodoItem from './components/TodoItem.vue'
 
const todos = ref([
  { id: 1, text: 'Купить хлеб', done: false },
  { id: 2, text: 'Позвонить Анне', done: false },
])
 
function removeTodo(id) {
  todos.value = todos.value.filter((todo) => todo.id !== id)
}
</script>
 
<template>
  <ul>
    <TodoItem
      v-for="todo in todos"
      :key="todo.id"
      :todo="todo"
      @remove="removeTodo(todo.id)"
    />
  </ul>
</template>

Кнопка «Удалить» в каждой строке убирает свою задачу. Родитель знает id из цикла и передаёт его в функцию.

Данные вместе с событием

Вторым аргументом emit можно передать значение. Добавим событие toggle, которое сообщает новое состояние флажка:

<!-- src/components/TodoItem.vue -->
<script setup>
defineProps({
  todo: { type: Object, required: true },
})
 
const emit = defineEmits(['remove', 'toggle'])
</script>
 
<template>
  <li>
    <input
      type="checkbox"
      :checked="todo.done"
      @change="emit('toggle', $event.target.checked)"
    >
    {{ todo.text }}
    <button @click="emit('remove')">Удалить</button>
  </li>
</template>
<!-- src/App.vue, фрагмент шаблона -->
<TodoItem
  v-for="todo in todos"
  :key="todo.id"
  :todo="todo"
  @toggle="(checked) => (todo.done = checked)"
  @remove="removeTodo(todo.id)"
/>

Отметка флажка вызывает toggle с true или false, и родитель записывает это значение в задачу.

Поток данных

НаправлениеМеханизмПример
Родитель → дочернийprops:todo="todo"
Дочерний → родительemit@remove="removeTodo(todo.id)"

Такое правило — данные вниз, события вверх — делает понятным, кто и где меняет состояние.

Частая ошибка

Забыть объявить событие в defineEmits. Если список событий есть, но нового в нём нет, Vue выведет в консоль предупреждение. Если же defineEmits нет вовсе, слушатель из родителя попадёт на корневой элемент компонента как обычный обработчик DOM. Для события с именем click это значит, что обработчик сработает дважды: от emit и от настоящего клика. Объявляйте все события, которые генерирует компонент.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.