defineProps, defineEmits та defineExpose у Vue.js
Макроси Script Setup
<script setup> у Vue 3 надає макроси компілятора, які спрощують оголошення компонентів. Ці макроси автоматично доступні — імпорти не потрібні.
defineProps
Оголосіть пропси, які компонент приймає:
vue
<script setup lang="ts">
// Оголошення на основі типів (рекомендується)
const props = defineProps<{
title: string
count?: number
items: string[]
user: { name: string; age: number }
}>()
// Доступ до пропсів
console.log(props.title)
</script>З значеннями за замовчуванням
vue
<script setup lang="ts">
const props = withDefaults(
defineProps<{
title: string
count?: number
theme?: 'light' | 'dark'
items?: string[]
}>(),
{
count: 0,
theme: 'light',
items: () => [], // Використовуйте фабричну функцію для об'єктів/масивів
}
)
</script>Оголошення під час виконання
vue
<script setup>
const props = defineProps({
title: { type: String, required: true },
count: { type: Number, default: 0 },
items: { type: Array, default: () => [] },
})
</script>defineEmits
Оголосіть події, які компонент може випускати:
vue
<script setup lang="ts">
const emit = defineEmits<{
change: [value: string]
submit: [data: { name: string }]
close: []
}>()
function handleChange(e: Event) {
emit('change', (e.target as HTMLInputElement).value)
}
function handleSubmit() {
emit('submit', { name: 'Alice' })
}
</script>defineExpose
Експонуйте методи/властивості компонента батьківському компоненту через рефери шаблону:
vue
<!-- ChildComponent.vue -->
<script setup>
import { ref } from 'vue'
const count = ref(0)
function reset() {
count.value = 0
}
function focus() {
// Логіка фокусування
}
// За замовчуванням нічого не експонується з <script setup>
// Явно експонуйте те, до чого можуть отримати доступ батьки:
defineExpose({ count, reset, focus })
</script>vue
<!-- ParentComponent.vue -->
<script setup>
import { ref } from 'vue'
import ChildComponent from './ChildComponent.vue'
const childRef = ref<InstanceType<typeof ChildComponent> | null>(null)
function resetChild() {
childRef.value?.reset() // ✅ Доступно завдяки defineExpose
childRef.value?.count // ✅ Доступно
}
</script>
<template>
<ChildComponent ref="childRef" />
<button @click="resetChild">Скинути дитину</button>
</template>defineModel (Vue 3.4+)
Спрощує прив'язку v-model:
vue
<!-- CustomInput.vue -->
<script setup>
const model = defineModel<string>()
// Еквівалентно: props.modelValue + emit('update:modelValue')
</script>
<template>
<input v-model="model" />
</template>
<!-- Parent.vue -->
<CustomInput v-model="name" />Іменовані моделі
vue
<script setup>
const firstName = defineModel<string>('firstName')
const lastName = defineModel<string>('lastName')
</script>
<!-- <UserForm v-model:firstName="first" v-model:lastName="last" /> -->Резюме
| Макрос | Призначення | Потрібен імпорт? |
|---|---|---|
defineProps | Оголосити пропси компонента | Ні |
defineEmits | Оголосити події компонента | Ні |
defineExpose | Експонувати API через реф шаблону | Ні |
defineModel | Двостороннє зв'язування (v-model) | Ні |
withDefaults | Значення за замовчуванням для пропсів | Ні |
Важливо:
Ці макроси є трансформаціями компілятора — вони не існують під час виконання і не потребують імпортів. Використовуйте defineProps з генераками TypeScript для типобезпечних пропсів, defineEmits для типізованих подій, defineExpose для контролю доступу батьків, а також defineModel (Vue 3.4+) для спрощеного v-model.
Коротка відповідь
Для співбесідиPremium
Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.