Skip to content

Component Events

Подразумевается, что вы уже изучили и разобрались с разделом Основы компонентов. Если нет — прочитайте его сначала.

Отправка и прослушивание событий

Компонент может генерировать пользовательские события непосредственно в выражениях шаблона (например, в обработчике v-on), используя встроенный метод $emit:

template
<!-- MyComponent -->
<button @click="$emit('someEvent')">нажми на меня</button>

Метод $emit() также доступен в экземпляре компонента как this.$emit():

js
export default {
  methods: {
    submit() {
      this.$emit('someEvent')
    }
  }
}

Родительский компонент может прослушать его, используя v-on:

template
<MyComponent @some-event="callback" />

Модификатор .once также поддерживается для слушателей событий компонента:

template
<MyComponent @some-event.once="callback" />

Как компоненты и входные параметры, имена событий обеспечивают автоматическое преобразование регистра. Обратите внимание, что мы испустили событие в регистре camelCase, но можем прослушать его с помощью слушателя в регистре kebab-case в родительском компоненте. Как и в случае с регистрацией входных параметров, мы рекомендуем использовать kebab-case регистр для прослушивания событий в шаблонах.

Совет

В отличие от собственных событий DOM, события, испускаемые компонентами, не всплывают. Вы можете слушать только события, испускаемые непосредственно дочерним компонентом. Если необходимо взаимодействие между родственными или глубоко вложенными компонентами, используйте внешнюю шину событий или глобальное управление состоянием.

Аргументы события

Иногда бывает полезно передать определенное значение вместе с событием. Например, мы можем захотеть, чтобы компонент <BlogPost> отвечал за то, насколько увеличить текст. В таких случаях мы можем передать $emit дополнительные аргументы, чтобы предоставить это значение:

template
<button @click="$emit('increaseBy', 1)">
  Увеличить на 1
</button>

Затем, когда мы прослушиваем событие в родителе, мы можем использовать встроенную стрелочную функцию в качестве слушателя, что позволит нам получить доступ к аргументу события:

template
<MyButton @increase-by="(n) => count += n" />

Или, если обработчик события является методом:

template
<MyButton @increase-by="increaseCount" />

Затем значение будет передано в качестве первого параметра этого метода:

js
methods: {
  increaseCount(n) {
    this.count += n
  }
}
js
function increaseCount(n) {
  count.value += n
}

Совет

Все дополнительные аргументы, переданные в $emit() после имени события, будут переданы слушателю. Например, при $emit('foo', 1, 2, 3) функция обработчика события получит три аргумента.

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

События генерируемые компонентом можно объявить с помощью defineEmits()опции emits:

vue
<script setup>
defineEmits(['inFocus', 'submit'])
</script>

Метод $emit, который мы использовали в <template> недоступен в разделе <script setup> компонента, но defineEmits() возвращает эквивалентную функцию, которую мы можем использовать вместо него:

vue
<script setup>
const emit = defineEmits(['inFocus', 'submit'])

function buttonClick() {
  emit('submit')
}
</script>

Макрос defineEmits() нельзя использовать внутри функции, он должен быть помещен непосредственно в <script setup>, как в примере выше.

Если вы используете явную функцию setup вместо <script setup> события должны быть объявлены с помощью опции emits, а функция emit доступна в контексте setup():

js
export default {
  emits: ['inFocus', 'submit'],
  setup(props, ctx) {
    ctx.emit('submit')
  }
}

Как и другие свойства контекста setup(), emit можно безопасно деструктурировать:

js
export default {
  emits: ['inFocus', 'submit'],
  setup(props, { emit }) {
    emit('submit')
  }
}
js
export default {
  emits: ['inFocus', 'submit']
}

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

vue
<script setup lang="ts">
const emit = defineEmits({
  submit(payload: { email: string, password: string }) {
    // возвращает `true` или `false`, чтобы показать
    // что проверка пройдена / не пройдена
  }
})
</script>

Если вы используете TypeScript с <script setup>, можно также объявить генерируемые события с помощью чистых аннотаций типов:

vue
<script setup lang="ts">
const emit = defineEmits<{
  (e: 'change', id: number): void
  (e: 'update', value: string): void
}>()
</script>

Подробнее: Типизирование пользовательских событий компонента

js
export default {
  emits: {
    submit(payload: { email: string, password: string }) {
      // возвращает `true` или `false`, чтобы показать
      // что проверка пройдена / не пройдена
    }
  }
}

См. также: Типизирование пользовательских событий компонента

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

Совет

Если в опции emits определено собственное событие (например, click), слушатель теперь будет прослушивать только события click, генерируемые компонентом, и больше не будет реагировать на собственные события click.

Валидация сгенерированных событий

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

Для добавления валидации событию необходимо указать функцию, которая получает аргументы, с которыми вызывался this.$emitemit и возвращает булево, определяющее является ли событие корректным или нет.

vue
<script setup>
const emit = defineEmits({
  // Без валидации
  click: null,

  // Валидация события submit
  submit: ({ email, password }) => {
    if (email && password) {
      return true
    } else {
      console.warn('Некорректные данные для события submit!')
      return false
    }
  }
})

function submitForm(email, password) {
  emit('submit', { email, password })
}
</script>
js
export default {
  emits: {
    // Без валидации
    click: null,

    // Валидация события submit
    submit: ({ email, password }) => {
      if (email && password) {
        return true
      } else {
        console.warn('Некорректные данные для события submit!')
        return false
      }
    }
  },
  methods: {
    submitForm(email, password) {
      this.$emit('submit', { email, password })
    }
  }
}
Component EventsУже загружено