Функции обратного вызова представляют еще один способ взаимодействия между родительским и дочерним компонентами: родительские компоненты могут определять функции, а вызываются они в дочерних компонентах.
Например, определим следующую веб-страницу:
<!DOCTYPE html> <html> <head> <title>Компоненты Vue 3</title> <meta charset="utf-8" /> </head> <body> <div id="app"> <h3>Value {{ count }}</h3> <counter :changefn="increase"></counter> </div> <script src="https://unpkg.com/vue"></script> <script> const app = Vue.createApp({ data(){ return { count: 0 } }, methods:{ increase(){ this.count++; } } }); app.component('counter', { props: ["changefn"], template: `<div><button v-on:click="changefn()">+</button></div>` }); app.mount('#app'); </script> </body> </html>
В данном случае объект приложения Vue определяет некоторый счетчик - переменную count. И также определеяет метод increase()
для
увеличения этого счетчика. Однако сам этот метод вызывается в дочернем компоненте counter. Сам ссылка на метод increase передается в компонент counter
как обычное свойство под названием "changefn":
<counter :changefn="increase"></counter>
В самом компоненте counter по нажатию на кнопку вызывается метод, переданный через параметр changefn.
<button v-on:click="changefn()">+</button>
В итоге при нажатии на кнопку будет вызываться метод родительского компонента, и мы увидем увеличение значения переменной count.
Рассмотрим более сложный пример:
<!DOCTYPE html> <html> <head> <title>Компоненты Vue 3</title> <meta charset="utf-8" /> </head> <body> <div id="app"> <h2>Список пользователей</h2> <userform :addfn="add"></userform> <div> <useritem v-for="(user, index) in users" :user="user" :key="index" :index="index" :removefn="remove"> </useritem> </div> </div> <script src="https://unpkg.com/vue"></script> <script> const app = Vue.createApp({ data(){ return { users:[ {name: 'Tom', age: 23}, {name: 'Bob', age: 26}, {name: 'Alice', age: 28} ] } }, methods:{ remove(index){ this.users.splice(index, 1); }, add(user){ this.users.push(user); } } }); app.component('userform', { props: ["addfn"], data() { return { user: {name:'', age:18} } }, template: `<div> <input type="text" v-model="user.name" /> <input type="number" v-model="user.age" /> <button v-on:click="addfn({name:user.name, age: user.age})">Add</button> </div>` }); app.component('useritem', { props: ["user", "index", "removefn"], template: `<div> <p>Name: {{user.name}} <br> Age: {{user.age}}</p> <button v-on:click="removefn(index)">Delete</button> </div>` }); app.mount('#app'); </script> </body> </html>
Объект Vue выводит на страницу массив элементов и определяет два метода для управления элементами: add (для добавления) и remove (для удаления).
Для добавления нового элемента определен компонент userform, который представляет форму с полями ввода. В этот компонент передается метод add в виде функции addfn:
<userform :addfn="add"></userform>
Причем функция addfn определена в компоненте userform через props:
Vue.component('userform', { props: ["addfn"],
При нажатии на кнопку эта функция будет вызываться, и ей будут передаваться введенные данные. Что фактически приведет к вызову метода add в родительском объекте Vue.
Аналогичная ситуация с компонентом useritem, который получает метод remove в виде функции removefn, которая также определяется через props. При нажатии на кнопку удаления вызывается функция removefn, ей передается индекс удаляемого элемента, и фактически будет идти вызов метода remove из объекта Vue.
Таким образом, в самих дочерних компонентах никаких действий по управлению массивом и объектами и по генерации событий не определено. Дочерние компоненты просто вызывают те методы, которые определены в родительском объекте.