Через props мы можем передать данные от родительского компонента в дочерний. Но что если мы хотим также передавать данные и в обратном направлении: от дочернего компонента к родителю? В этом случае необходимо определить свои события. Дочерний компонент будет генерировать событие с помощью вызова this.$emit(имя_события), а родительский компонент будет отлавливать это событие с помощью установки атрибута v-on:название_события и при получении события поизводить определенные действия. Например:
<!DOCTYPE html> <html> <head> <title>Компоненты Vue.js</title> <meta charset="utf-8" /> </head> <body> <div id="app"> <h2>Hello, {{name}}</h2> <useredit :user="name" v-on:userchange="change"></useredit> </div> <script src="https://unpkg.com/vue@2.7.14/dist/vue.js"></script> <script> Vue.component('useredit', { props: ["user"], data: function () { return { userName: this.user} }, template: '<div><input type="text" v-model="userName" v-on:input="onUserChange" /><p>Name: {{userName}}</p></div>', methods: { onUserChange: function(){ this.$emit('userchange', this.userName); } } }); new Vue({ el: "#app", data: { name: 'Tom' }, methods:{ change: function(value){ this.name = value; } } }); </script> </body> </html>
В данном случае определяется событие userchange. В реальности в JavaScript не существует подобного события, мы его определяем сами.
В шаблоне компонента элемент ввода связан двусторонней привязкой со значением со свойством userName. Также для этого элемента установлен обработчик события input:
<input type="text" v-model="userName" v-on:input="onUserChange" />
То есть при вводе в это текстовое поле будет вызываться метод onUserChange. В этом методе через вызов this.$emit('userchange', this.userName);
генерируем событие userchange и передаем в этом событии измененное значение свойства userName (так как это свойство связано двусторонней привязкой с полем ввода, то при вводе
в текстовое поле изменится и свойство user).
onUserChange: function(){ this.$emit('userchange', this.userName); }
Чтобы отловить это событие в объекте Vue на дочернем компоненте определен атрибут v-on:userchange
:
<useredit :user="name" v-on:userchange="change"></useredit>
То есть поскольку в дочернем компоненте генерируется событие userchange, то соответственно здесь и атрибут имеет определение v-on:userchange
.
Этому событию сопоставлен метод change:
change: function(value){ this.name = value; }
Параметр value представляет то значение, которое передается в дочернем компоненте через вызов this.$emit('userchange', this.userName);
,
то есть this.userName.
В итоге при вводе данных в дочернем компоненте useredit сработает обработчик события input - метод onUserChange, который сгенерирует событие namechange, которое в свою очередь будет обработано в родительском объекте в методе change.
Начиная с версии 2.3 был добавлен модификатор sync, который позволяет в ряде случаев сократить код использования событий. В частности, перепишем предыдущий пример следующим образом:
<!DOCTYPE html> <html> <head> <title>Компоненты Vue.js</title> <meta charset="utf-8" /> </head> <body> <div id="app"> <h2>Hello, {{name}}</h2> <useredit :user.sync="name"></useredit> </div> <script src="https://unpkg.com/vue@2.7.14/dist/vue.js"></script> <script> Vue.component('useredit', { props: ["user"], data: function () { return { userName: this.user} }, template: '<div><input type="text" v-model="userName" v-on:input="onUserChange" /><p>Name: {{userName}}</p></div>', methods: { onUserChange: function(){ this.$emit('update:user', this.userName) } } }); new Vue({ el: "#app", data: { name: 'Tom' } }); </script> </body> </html>
В данном случае строка
<useredit :user.sync="name"></useredit>
будет сокращенем строки:
<useredit :user="name" v-on:update:user="val => name = val"></useredit>
Но в дочернем компоненте также необходимо вызывать данное событие:
onUserChange: function(){ this.$emit('update:user', this.userName) }