Руководство по использованию Emit в Vue

В Vue данные обычно передаются от родительских компонентов к их дочерним однонаправленно. Это передается с помощью props, которые являются свойствами или атрибутами, которые мы даем компонентам.

Например, если мы назовем компонент PageOne, который имеет свойство name, то это свойство name станет доступным в самом компоненте PageOne, позволяя нам делать с ним то, что мы хотим. Таким образом, данные передаются в дочерний компонент, когда мы объявляем их в родительском компоненте или странице:

В большинстве сценариев реквизиты позволяют нам делать с данными все, что нам нужно. Однако иногда нам нужно передавать данные вверх — от дочернего компонента к его родителю. Для этого мы используем $emit, который позволяет нам отправлять данные вверх, а затем запускать событие в родительском компоненте, если произойдет событие $emit.

Как работает $emit в Vue

Есть три способа вызвать $emit в Vue, в зависимости от того, используете ли вы API Options, API Composition или инлайнинг событий $emit. Если вы не уверены, вы можете прочитать о разнице между Composition API и Options API здесь.

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

<template>
    <button @click="$emit('counterEvent')">Click Me</button>
</template>
Вход в полноэкранный режим Выход из полноэкранного режима

Этот компонент хранится в файле под названием Counter.vue. Наш компонент не может быть изменен, поскольку он используется в других местах, но у него есть событие $emit, запускаемое при каждом щелчке на нем. Это прекрасно, поскольку мы можем использовать его в нашем родительском компоненте.

А что если мы захотим добавить этот компонент куда-нибудь — например, в наш файл App.vue — и использовать его для отображения значения нашего счетчика. Давайте попробуем сделать это сейчас:

<template>
    <h1>{{ counter }}</h1>
    <Counter @counter-event="incrCounter"/>
</template>

<script>
import Counter from './Counter.vue'
export default {
    // Add our components
    components: {
      Counter
    },
    // Store our data
    data() {
        return {
            counter: 0
        }
    },
    methods: {
        incrCounter: function() {
            this.counter += 1;
        }
    }
}
</script>
Войти в полноэкранный режим Выйти из полноэкранного режима

Давайте разберем это на части — во-первых, мы включаем наш Counter. Поскольку у него есть событие $emit под названием counterEvent, мы можем прикрепить его к нашему Counter HTML. Каждый раз, когда $emit срабатывает, срабатывает counterEvent, а значит и функция в этом свойстве. Здесь мы запускаем incrCounter каждый раз, когда срабатывает counterEvent.

Делая это, мы также увеличиваем наши данные counter на 1, поскольку именно это делает incrCounter. Таким образом, мы передали событие щелчка вверх нашему родительскому компоненту.

Случай с кебабом

Вы можете заметить, что когда мы определяли наше событие $emit, мы использовали верблюжий регистр (counterEvent), но при отслеживании события мы использовали кебабный регистр (counter-event).

В Vue 3 можно использовать counterEvent и counter-event взаимозаменяемо, поскольку Vue 3 автоматически преобразует counterEvent в counter-event. В Vue 2 этой функции нет, поэтому просто используйте counter-event для обоих вариантов.

Передача данных с помощью $emit

Допустим, вместо этого мы хотим, чтобы наш компонент определял, на сколько должен увеличиться counterEvent. Если мы хотим сделать это, мы можем передать второй аргумент функции $emit, который является значением:

<template>
    <button @click="$emit('counterEvent', 2)">Click Me</button>
</template>
Войти в полноэкранный режим Выйти из полноэкранного режима

Здесь мы передаем значение 2 нашему counterEvent. Давайте вернемся к нашему файлу App.vue. Чтобы использовать это значение в counterEvent, нам нужно записать его как функцию. Ниже, n — это значение:

<template>
    <h1>{{ counter }}</h1>
    <Counter @counter-event="(n) => incrCounter(n)"/>
</template>

<script>
import Counter from './Counter.vue'
export default {
    // Add our components
    components: {
      Counter
    },
    // Store our data
    data() {
        return {
            counter: 0
        }
    },
    methods: {
        incrCounter: function(value) {
            this.counter += value;
        }
    }
}
</script>
Вход в полноэкранный режим Выйти из полноэкранного режима

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

Использование $emit с API Options

Мы показали довольно простой пример, но мы также могли бы написать наш дочерний компонент Counter.vue с использованием функции. Вот пример с API Options, использующий this.$emit:

<template>
    <button @click="emitFunction">Click Me</button>
</template>

<script>
export default {
  emits: [ 'counterEvent' ],
    methods: {
        emitFunction: function() {
            this.$emit('counterEvent', 2)
        }
    }
}
</script>
Войти в полноэкранный режим Выйти из полноэкранного режима

Это может оказаться немного более чистым способом использования $emit, особенно если вы хотите делать другие вещи наряду с использованием $emit при нажатии на кнопку.

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

Вы можете заметить, что мы также определили наше событие emit в emits на прототипе. Это хорошая практика по двум причинам:

  • Это позволяет вам самодокументировать код, показывая, какие события emit возможны в данном компоненте.
  • Это помогает отслеживать устаревшие события, поскольку Vue будет выдавать ошибку, если используется событие emit, но оно не найдено в массиве emits.

Использование $emit с API композиции

Мы можем использовать $emit с API Composition — единственная разница в том, что вместо этого мы должны использовать defineEmits.

<template>
    <button @click="emitFunction">Click Me</button>
</template>

<script setup>
import { defineEmits } from 'vue'

const emit = defineEmits(['counterEvent']);
const emitFunction = function() {
    emit('counterEvent', 2)
}
</script>
Вход в полноэкранный режим Выход из полноэкранного режима

defineEmits используется для определения полного списка всех допустимых событий emit. Здесь у нас только одно, counterEvent. Если бы у вас было несколько, вы могли бы определить их так:

const emit = defineEmits(['counterEvent', 'anotherEvent', 'finalEvent']);
Вход в полноэкранный режим Выход из полноэкранного режима

Если вы используете событие emit, не указанное в defineEmits, Vue выдаст предупреждение, аналогичное использованию emits в API Options. В противном случае вы можете использовать функцию emit(), чтобы эмитировать как обычно, без необходимости использовать API Options.

Заключительные мысли и лучшие практики

Emit — это мощный инструмент для отправки данных обратно в родительский модуль, когда это необходимо. Это означает, что потоки данных в Vue могут быть двусторонними. При определении кода emit следует придерживаться двух основных лучших практик:

  • Всегда определяйте события emit либо в emits, либо в defineEmits, что поможет вам сохранить ваш код чистым и хорошо документированным.
  • Обычным соглашением в Vue 3 является использование кебабного регистра (this-is-kebab-case) в HTML, и верблюжьего регистра (thisIsCamelCase) в сценарии. Поэтому и здесь лучше всего следовать этому соглашению.

Надеюсь, вам понравилось это руководство о том, как работает $emit. Оставайтесь с нами, чтобы узнать больше о Vue.

Оцените статью
Procodings.ru
Добавить комментарий