Как компоненты Vue общаются друг с другом?

JuniorVue.js #vue #components

Вопрос

Какие есть способы передачи данных между компонентами Vue?

Короткий ответ

Базовый принцип — "props вниз, события вверх" (props down, events up): родитель передаёт данные через props, дочерний компонент сообщает об изменениях через emit. Для более сложных случаев есть slots и provide/inject.

Подробный ответ

  • props — однонаправленный поток данных от родителя к потомку. Дочерний компонент не должен мутировать props напрямую.
  • emit — потомок сообщает о событии родителю (emit('update:modelValue', value) — основа v-model).
  • slots — позволяют родителю передавать разметку внутрь компонента, а не только данные. Именованные и scoped slots дают доступ к данным дочернего компонента из шаблона родителя.
  • provide/inject — передача данных через несколько уровней вложенности без "прокидывания" props через каждый промежуточный компонент (prop drilling). Хорошо подходит для тем оформления, конфигурации, авторизации.
  • Для несвязанных компонентов — общее состояние (Pinia) или шина событий (используется редко в Vue 3).

Пример

<!-- Parent.vue -->
<script setup>
import { ref } from 'vue'
const title = ref('Привет')
function handleClose() { title.value = '' }
</script>
<template>
  <Card :title="title" @close="handleClose">
    <template #footer>
      <button>Действие</button>
    </template>
  </Card>
</template>
<!-- Card.vue -->
<script setup>
defineProps<{ title: string }>()
defineEmits<{ close: [] }>()
</script>
<template>
  <div>
    <h2>{{ title }}</h2>
    <slot />
    <slot name="footer" />
  </div>
</template>

Дополнительные вопросы

  • Как реализовать двустороннее связывание через v-model в кастомном компоненте?
  • Чем scoped slot отличается от обычного?
  • Когда provide/inject предпочтительнее Pinia?