Одной из частых задач при организации компонентов во Vue составляет организация взаимодействия между компонентами, которые находятся на одном уровне, то есть являются сестринскими.
В этом случае взаимодействие происходит через родительский компонент. Например, определим два дочерних компонента, которые взаимодействуют через родительский компонент:
<!DOCTYPE html> <html> <head> <title>Компоненты Vue 3</title> <meta charset="utf-8" /> </head> <body> <div id="app"> <h2>User</h2> <useredit :name="user" @userchange="change"></useredit> <userinfo :name="user" @userreset="reset"></userinfo> </div> <script src="https://unpkg.com/vue"></script> <script> const app = Vue.createApp({ data(){ return { user:'Tom' } }, methods:{ change(name){ this.user = name; }, reset(){ this.user = 'Tom'; }, } }); app.component('useredit', { props: ["name"], template: '<div><input v-model="username" /><button @click="save">Save</button></div>', data(){ return { username: this.name } }, watch: { name(newVal) { this.username = newVal; } }, methods:{ save(){ this.$emit("userchange", this.username); } } }); app.component('userinfo', { props: ["name"], template: `<div><p>Имя: {{name}}</p><button @click="reset">Reset</button></div>`, methods:{ reset(){ this.$emit("userreset"); } } }); app.mount('#app'); </script> </body> </html>
Ключевым моментом здесь является то, что данные, которыми манипулируют оба компонента, хранятся как данные все приложения Vue. В данном случае оба дочерних компонента useredit и userinfo принимают от объекта приложения Vue имя пользователя. То есть оба компонента используют те данные, которые определены в объекте приложения Vue. Вместо объекта приложения Vue это мог бы быть другой компонент, который был бы родительским по отношению к userinfo и useredit.
Первый дочерний компонент - useredit получает данные от родителя через свойство name
props: ["name"],
Однако здесь мы сталкиваемся со следующей задачей. Параметр props передает свойства только для чтения, которые мы не можем изменять. Однако в компоненте useredit мы хотим изменять свойство name. Более того передавать измененное значение другому компоненту и при этом отслеживать, не изменил ли другой компонент сам значение свойства name. То есть необходимо передавать во вне изменения и при этом отслеживать, не произошли ли вне компонента изменения со свойством name.
Чтобы свойство name можно было изменять, компонент useredit определяет новое свойство username:
data(){ return { username: this.name } },
Это свойство username привязанно двусторонней привязкой к текстовому полю:
<input v-model="username" /><button @click="save">Save</button>
При нажатии кнопки рядом с текстовым полем вызывается метод save
, который, в свою очередь,
генерирует событие userchange
:
save(){ this.$emit("userchange", this.username); }
Через событие userchange объект приложения Vue получит измененное имя пользователя и произведет необходимые изменения:
change(name){ this.user = name; },
Чтобы компонент useredit также мог отслеживать внешние изменения со свойством name, он определяет наблюдаемое свойство watcher:
watch: { name(newVal) { this.username = newVal; } }
В качестве параметра свойству передается новое значение свойства name. В итоге при всех изменениях сработает это свойство, что приведет к переустановке значения в username.
Второй дочерний компонент - userinfo также через свойство name из props получает от приложения Vue имя пользователя:
props: ["name"]
Однако этот компонент напрямую не изменяет значение name, а при нажатию на кнопку генерирует событие userreset
reset(){ this.$emit("userreset"); }
Приложение Vue отслеживает это событие и при его возникновении сбрасывает имя пользователя в изначальное:
reset(){ this.user = 'Tom'; },
То есть объект приложения Vue здесь служит медиатором, а непосредственно между собой компоненты не взаимодействуют.