Батько отримує доступ до дочірнього компонента через template ref:
<script setup>
import { useTemplateRef } from 'vue';
import VideoPlayer from './VideoPlayer.vue';
const player = useTemplateRef('player'); // Vue 3.5+; раніше - const player = ref(null)
function startOver() {
player.value?.seek(0);
player.value?.play();
}
</script>
<template>
<VideoPlayer ref="player" />
<button @click="startOver">Спочатку</button>
</template>
Але компоненти з <script setup> закриті за замовчуванням: через ref батько не бачить нічого - ні змінних, ні функцій дитини. Те, що можна викликати ззовні, дитина оголошує явно:
<!-- VideoPlayer.vue -->
<script setup>
import { useTemplateRef } from 'vue';
const video = useTemplateRef('video');
function play() { video.value.play(); }
function seek(seconds) { video.value.currentTime = seconds; }
defineExpose({ play, seek });
</script>
<template>
<video ref="video" src="/intro.mp4"></video>
</template>
Це навмисне рішення: публічний інтерфейс компонента - props, events, slots і явно відкриті методи, а не будь-яка внутрішня змінна.
Коли виклик методу дитини доречний - імперативні дії, які погано виражаються через стан:
- фокус на полі (
input.focus()), прокрутка до елемента; - керування медіа (play, pause, seek);
- відкриття модального вікна сторонньої бібліотеки, скидання форми.
Коли краще інакше: якщо батько змінює дані дитини - це props чи v-model. Виклик методів для синхронізації стану робить потік даних непрозорим: незрозуміло, хто й коли змінив стан.
Що варто знати:
- ref заповнюється після монтування - у
setupбатька він щеnull; звертатися вonMountedчи обробниках подій; - ref на компонент усередині
v-ifстаєnull, коли компонент прибрано, - звідси?.; refуv-forдає масив екземплярів;- TypeScript: тип відкритого API береться з
defineExpose-useTemplateRef<InstanceType<typeof VideoPlayer>>('player')чи автоматичне виведення в Vue 3.5 з Volar.