В этом видео мы с вами разберем, как можно передавать данные из child компоненты в parent. Например, у нас есть логин форма, которая является чайл компонентом. При отправке формы мы хотим передать логин и пароль в парент компонент.
В Vue есть несколько способов сделать это. На данный момент у меня создан пустой проект webpack-simple из vue-cli и в нем есть только компонент App.
Давайте создадим этот дочерний компонент с логин формой. В ней должно быть два инпута, для логина и пароля и кнопка submit.
LoginForm.vue
<template>
<div>
<h3>Login form</h3>
<div>
<div>
<label>Email:</label>
<input type='text' />
</div>
<div>
<label>Password:</label>
<input type='password' />
</div>
<div>
<button>Login</button>
</div>
</div>
</div>
</template>
Также, мы должны импортировать наш компонент в App и добавить в локальные компоненты.
App.vue
import loginForm from './LoginForm.vue'
export default {
...
components: {
loginForm
}
}
Теперь мы можем отрендерить нашу форму в шаблоне App.
App.vue
<loginForm />
Как мы видим, наша форма успешно отрендерилась в браузере.
Теперь давайте добавить v-model для инпутов.
LoginForm.vue
<input type='text' v-model='email' />
...
<input type='password' v-model='password' />
Мы также должны создать значения по умолчанию для email и password.
LoginForm.vue
data () {
return {
email: '',
password: ''
}
}
Теперь нам нужно навесить клик и создать метод, который будет вызываться.
LoginForm.vue
<button @click='login'>Login</button>
methods: {
login () {
console.log('login', this.email, this.password)
}
}
Как мы видим в браузере, наш компонент успешно работает и мы получаем емейл и пароль внутри метода login.
Как же мы теперь можем передать эти данные в парент?
Первый способ, это с использованием this.$emit. emit построен на принципе publish/subscribe. Если вы не помните, что это за паттерн, то я оставлю ссылку на видео про этот паттерн в тексте видео. Идея заключается в том, что мы емитим что-то в чайл компоненте и случаем этот евент в парент компоненте.
LoginForm.vue
methods: {
login () {
this.$emit('login', {
email: this.email,
password: this.password
})
}
}
Здесь мы вызвали $emit функцию внутри логин метода. Первым аргументом мы передает имя евента. Это может быть любая строка. Вторым аргументом мы передаем данные, которые относятся к этому евенту. В нашем случае мы передаем емейл и пароль в обьекте.
Теперь мы можем слушать этот емит в нашем App компоненте. Мы должны добавит кастомный евент с таким же именем, с которым мы эмитили евент.
App.vue
<loginForm @login='onLogin' />
То есть, мы хотим вызвать метод onLogin, когда LoginForm заэмитила логин евент. И давайте добавим onLogin метод
App.vue
methods: {
onLogin (data) {
console.log('child component said login', data)
}
}
Как вы видите, в onLogin мы получим первым параметром данные, которые мы передали в emitе. Если мы посмотрим в браузер, то все работает.
Итак еще раз, как это работает.
В этом случае наши child и parent компоненты абсолютно не связаны. Это конечно хорошо, но в этом и минус. Мы никогда не узнаем, у действительно ли парент слушает наш емит.
Есть также и другой способ передать данные из чайлда в парент. И это больше способ в стиле React и на мой взгляд он более наглядный, так как код легче дебажить. Мы можем просто передать в child компонент функцию из parent компонента и вызывать ее когда нам нужно.
Давайте изменим loginForm, чтобы мы могли передавать функцию.
App.vue
<loginForm :onLogin='onLogin' />
Не забывайте, что мы использовали v-bind, чтобы пробросить onLogin. Теперь мы должны добавить onLogin в props логин формы.
LoginForm.vue
export default {
props: ['onLogin']
...
}
Теперь мы можем вместо эмита вызвать onLogin метод и получить такой же результат.
LoginForm.vue
login () {
this.onLogin({
email: this.email,
password: this.password
})
}
Если мы посмотрим в браузер, то все работает как и раньше. Но в этом случае мы можем добавить валидацию props и это нам очень облегчит дебаг в будущем.
Если у вас возникли какие-то вопросы или комментарии, пишите их прямо под этим видео.