В Vue 3 есть два основных способа установить связь между дочерними и родительскими объектами. Использование реквизита и использование хранилища Vuex. В этом уроке мы рассмотрим оба ниже.
Общение ребенка с родителями с помощью реквизита
Первый способ, которым дочерние компоненты могут взаимодействовать со своими родительскими компонентами без использования дополнительных узловых пакетов, — это использовать функцию props платформы Vue. Возможно, вы использовали props раньше для передачи данных от родителя к дочернему, но с несколькими небольшими изменениями мы можем передать изменения данных обратно родителю.
То, что вы, возможно, уже знаете о реквизитах для передачи данных от родителя к дочернему, вероятно, выглядит примерно так:
<child :counter="counter" />
Теперь, если мы хотим, чтобы значение counter
реагировало на то, что происходит в дочернем элементе, мы можем сделать это, просто добавив v-model
к реквизиту следующим образом.
<child v-model:counter="counter" />
Допустим, ребенку может понадобиться что-то сделать со значением счетчика. Ваш код может выглядеть примерно так
<template> <div>Child Counter: {{ counter }} </div> <button @click="increment">Increment Counter</button> </template> <script> export default { props: { counter: { type: Number } }, data: () => ({ childCounter: 0 }), created() { // the prop needs to be re-assigned here. Vue doesn't like prop mutation this.childCounter = this.counter }, methods: { increment() { this.childCounter++ } } } </script>
Но это не обновляет значение счетчика, о котором знает родитель. Так что же нам делать?
Мы уже сказали дочернему компоненту в родительском компоненте прослушивать обновления для счетчика с помощью v-model
. Чтобы подключиться к этому слушателю, мы изменим наш метод приращения с помощью this.$emit('update:myProp', newPropValue)
increment() { this.childCounter++ this.$emit('update:counter', this.childCounter) }
Полный код выглядит так:
Родительский компонент
#Parent.vue <template> <div>Parent Counter: {{ counter }}</div> <child v-model:counter="counter" /> </template> <script> import Child from './Child' export default { components: { Child, }, data: () => ({ counter: 0, }), } </script>
Дочерний компонент
<template> <div>Child Counter: {{ childCounter }} </div> <button @click="increment">Increment Counter</button> </template> <script> export default { props: { counter: { type: Number } }, data: () => ({ childCounter: 0 }), created() { // the prop needs to be re-assigned here. Vue doesn't like prop mutation this.childCounter = this.counter }, methods: { increment() { this.childCounter++ this.$emit('update:counter', this.childCounter) } } } </script>
Взаимодействие ребенка и родителя с Vuex Store
Использование props в компонентах — это всего лишь один из способов, с помощью которого ребенок может передавать изменения данных родителям. Vue предлагает нам еще один способ достичь этой цели с помощью Vuex Store. Хранилище — это место, где данные хранятся в течение всего сеанса в нашем приложении. Чтобы начать работу с Vuex add, вам нужно добавить его в свое приложение. Нам нужно добавить vuex@next
в наш проект, а не vuex
, потому что vuex@next
работает с Vue 3, а vuex
все еще работает с Vue 2 на момент написания этой статьи.
$>npm i vuex@next
Затем нам нужно настроить наш магазин в приложении. Сначала добавим файл сценария магазина. Мы добавим к этому позже
#src/store/store.js import { createStore } from 'vuex' export default createStore({})
А затем зарегистрируйте магазин с вашим приложением
#src/main.js import { createApp } from 'vue' import App from './App.vue' import store from './store/store' const app = createApp(App) app.use(store) app.mount('#app')
Как только это будет сделано, нам понадобится state
со значением, которое содержит counter
, а также способ mutate
этого состояния.
import { createStore } from 'vuex' const state = { counter: 0 } const mutations = { increment: (state) => state.counter++ } export default createStore({ state, mutations })
Чтобы получить это значение из хранилища, достаточно добавить в компонент вычисляемое свойство, которое возвращает значение счетчика в хранилище. Это может быть где угодно в приложении, где вам нужно значение, будь то родитель дочернего элемента, выполняющего мутацию, или совершенно другое место.
computed: { counter() { return store.state.counter } }
И чтобы увеличить счетчик, нам просто нужно commit
a mutation
в методе вашего компонента
methods: { increment() { store.commit('increment') } }
Результирующий код будет выглядеть так:
Дочерний компонент
<template> <div>Child Counter: {{ counter }} </div> <button @click="increment">Increment Counter</button> </template> <script> import store from '../store/store' export default { computed: { counter() { return store.state.counter } }, methods: { increment() { store.commit('increment') } } } </script>
Родительский компонент
<template> <div>Parent Counter: {{ counter }}</div> <child /> </template> <script> import store from '../store/store' import Child from './Child' export default { components: { Child, }, computed: { counter() { return store.state.counter } } } </script>
Вывод
Мы изучили два основных способа взаимодействия компонентов в Vue 3. Конечно, есть и другие решения и разные реализации магазина. Вы должны найти тот, который лучше всего подходит для вас и задачи, которую вы пытаетесь выполнить.
Мой исходный код, включая приведенные выше примеры, можно найти здесь: https://github.com/jacobtshirt/vue-child-parent-commucation
Документы Vue: https://v3.vuejs.org/
Документы Vuex: https://next.vuex.vuejs.org/