Проблема передачи событий и данных из дочернего компонента к родительскому.

Когда мы с вами работаем с какими-то элементами в разметке нашей страницы, мы можем добавлять для них какие-то обработчики событий. 

<input type="text" @change="...">

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

<button @click="...">Кнопка</button>

Точно также мы можем, например, добавить для элемента button событие клик, и в момент, когда произошёл клик по нашей кнопке, будет выполняться какая-то логика. 

Как мы с вами знаем, наши компоненты, которые мы используем в родительских элементах, они тоже по сути являются элементами разметки, которые будут выводить какое-то содержимое на веб-страницу. 

Соответственно, для этих элементов, компонентов, которые используются в родительском компоненте, хотелось бы тоже использовать какие-то события. 

Когда внутри компонента произошло какое-то событие, хотелось бы его поймать и выполнить какой-то набор действий в его родительском компоненте. 

Довольно частая задача. Какие-то данные изменились в нашем дочернем компоненте, и нам нужно поймать это событие и каким-то образом выполнить какие-то действия. 

Действительно во Vue есть такой функционал, который позволяет нам создавать свои пользовательские события для дочерних компонентов. 

Компонент может в какой-то момент времени сказать, что у меня что-то произошло, произошло какое-то событие в какой-то момент времени, в каком-то месте кода, и соответственно он уведомит об этом родительский компонент. 

Как это технически реализовать? Знакомимся с emit.

Например, нам нужно вызвать метод test1 в родительском компоненте в тот момент, когда пользователь кликнул по кнопке в дочернем компоненте.

<template>

 <ChildComponent></ChildComponent>

</template>




<script>

import ChildComponent from "@/components/ChildComponent.vue";




export default {

 name: 'App',

 components: {

   ChildComponent

 },

 methods: {

   test1(val) {

     console.log(val);

  },

  test2() {

     console.log('test');

  }

 }

};

</script>

Для того чтобы это сделать, для того, чтобы сгенерировать такое кастомное (пользовательское) событие, мы можем воспользоваться такой служебной конструкцией, как emit.

Emit позволяет нам создать своё собственное событие. Мы сами придумываем название этого события. Например, мы можем назвать его onButtonClick.

<button @click="$emit('onButtonClick')"></button>

Теперь в момент клика по кнопке, в родительском компоненте, мы можем поставить знак собачку, как мы это делали для встроенных в Vue событий, click и так далее, и прописать имя нашего события onButtonClick и вызываем тот метод, который хотим, чтобы у нас отработал

<ChildComponent @onButtonClick="test1"></ChildComponent>

Например, метод test1. 

Таким образом, мы, создали своё собственное событие onButtonClick и передали его в родительский компонент, чтобы он мог его слушать. 

Если нам нужно передавать какие-то данные. Например, у нас есть много кнопочек и мы хотим сказать, сообщить, по какой именно кнопке был выполнен клик. 

Для этого мы можем передать в виде аргумента. Т.е. взять и передать здесь какие-то данные. 

Например, давайте попробуем передать строку test.

<button @click="$emit('onButtonClick','test')"></button>

Теперь наша задача в test1 взять value и вывести его в консоль.

methods: {

  test1(val) {

    console.log(val);

 }

}

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

<ChildComponent @onButtonClick="test1"></ChildComponent>

Вызов emit из методов.

Мы можем вынести вызов emit в методы. 

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

<template>

   <button @click="onClick"></button>

</template>

<script>

export default {

 name: "mainVue",

 data() {

   return {

     text: 'тест'

   }

 },

 methods: {

   onClick() {

     this.$emit('onButtonClick','test')

  }

 }

}

</script>

Но, если мы пропишем скобки в названии метода и будем кликать по кнопке, получаем undefined. 

<button @click="onClick()"></button>

Почему? Потому что здесь у нас, как бы, получилась такая ситуация, что аргумент, который передался, он у нас затерялся такой формой записи.

Если мы хотим использовать такую форму записи, нам нужно воспользоваться такой конструкцией

<button @click="(event) => onClick(event)"></button>

Мы получили этот аргумент и теперь этот аргумент у нас не будет теряться, он будет передаваться внутрь внутрь нашего test1. 

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