Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Як зробити v-model на власному компоненті через defineModel?

v-model на компоненті - це скорочення для пари «prop + подія оновлення». З Vue 3.4 для цього є макрос defineModel():

<!-- QuantityInput.vue -->
<script setup>
const quantity = defineModel({ type: Number, default: 1 });
</script>

<template>
  <button type="button" @click="quantity--" :disabled="quantity <= 1">-</button>
  <span>{{ quantity }}</span>
  <button type="button" @click="quantity++">+</button>
</template>
<QuantityInput v-model="item.qty" />

defineModel() повертає ref: читання дає значення від батька, запис - надсилає подію update:modelValue, і батько оновлює свою змінну.

Що генерує компілятор (так писали до 3.4 і це варто розуміти):

const props = defineProps(['modelValue']);
const emit = defineEmits(['update:modelValue']);
// v-model="item.qty" на батьку = :modelValue="item.qty" @update:modelValue="v => item.qty = v"

Кілька v-model на одному компоненті - іменовані моделі:

<script setup>
const firstName = defineModel('firstName');
const lastName = defineModel('lastName');
</script>
<UserName v-model:first-name="user.first" v-model:last-name="user.last" />

Модифікатори (власні чи вбудовані на кшталт .trim) читаються з другого елемента й обробляються в set:

const [title, modifiers] = defineModel({
  set(value) {
    return modifiers.capitalize ? value.charAt(0).toUpperCase() + value.slice(1) : value;
  },
});

Пастки:

  • значення за замовчуванням в defineModel({ default: ... }) і відсутність v-model на батьку: дитина бачить своє значення, а батько - undefined. Стан розсинхронізований;
  • об'єкт у моделі: зміна поля model.value.name = 'x' змінює об'єкт батька напряму, без події. Для об'єктів правильніше присвоювати новий об'єкт (model.value = { ...model.value, name: 'x' }) або мати окремі моделі на поля;
  • для нативного поля всередині - простіше прокинути v-model далі: <input v-model="value">, де value = defineModel().

Докладніше в документації: v-model на компонентах

Перевір себе

20 випадкових питань за спробу, після завершення - розбір кожної помилки

Схожі питання