v-model на компоненті - це скорочення для пари «prop + подія оновлення»:
<PriceInput v-model="price" />
<!-- те саме, що -->
<PriceInput :modelValue="price" @update:modelValue="(v) => price = v" />
До Vue 3.4 дочірній компонент мусив оголосити prop, подію і зв'язати їх вручну. defineModel (3.4+) робить це одним рядком:
<!-- PriceInput.vue -->
<script setup lang="ts">
const model = defineModel<number>({ required: true })
</script>
<template>
<input type="number" v-model="model" />
</template>
model - ref: читання повертає значення від батька, присвоєння model.value = 10 випромінює update:modelValue. Компілятор створює і prop modelValue, і подію автоматично.
Кілька моделей і назви:
<!-- батько -->
<DateRange v-model:from="startDate" v-model:to="endDate" />
<!-- DateRange.vue -->
<script setup lang="ts">
const from = defineModel<string>('from')
const to = defineModel<string>('to')
</script>
Модифікатори (v-model.trim) доступні через деструктуризацію:
const [model, modifiers] = defineModel<string>({
set(value) {
return modifiers.trim ? value.trim() : value
},
})
Значення за замовчуванням і розсинхронізація. Якщо модель має default, а батько не передав їй значення (його змінна undefined), дочірній компонент працюватиме зі своїм значенням за замовчуванням: у батька undefined, у дитини, наприклад, 1. Документація прямо попереджає про цю розсинхронізацію - надійніше, щоб початкове значення задавав батько.
Пастки:
model.value.push(x)для масиву змінює об'єкт батька напряму, без події - краще присвоювати новий масив (model.value = [...model.value, x]);v-modelна<input>усередині з тим самимmodel- нормальний і найкоротший шлях обгорнути нативне поле.