1. Слоты и v-slot: как компоненты становятся гибкими
Что такое слот и зачем он нужен
Синтаксис
v-slotи его короткая запись (#default,#header,#footer)Пример с одним слотом (карточка или layout-компонент)
Пример с несколькими слотами:
<BaseCard> <template #header> <h3>Заголовок карточки</h3> </template> <template #default> <p>Основное содержимое карточки.</p> </template> <template #footer> <button>Подробнее</button> </template> </BaseCard><!-- BaseCard.vue --> <template> <div class="card"> <header><slot name="header" /></header> <main><slot /></main> <footer><slot name="footer" /></footer> </div> </template>Пояснение: так компоненты становятся универсальными контейнерами, в которые можно "вставить" любую разметку.
2. v-model и defineModel: двусторонняя связь по-новому
Как
v-modelработает под капотомmodelValueи@update:modelValue— классический паттернVue 3.3+:
defineModel()— упрощённая декларация модели в дочернем компоненте<!-- ChildInput.vue --> <script setup> const text = defineModel() // автоматически создаёт prop и emit </script> <template> <input v-model="text" placeholder="Введите текст" /> </template><!-- App.vue --> <template> <ChildInput v-model="username" /> <p>Вы ввели: {{ username }}</p> </template> <script setup> import ChildInput from './ChildInput.vue' import { ref } from 'vue' const username = ref('') </script>Несколько
v-model:<!-- ChildComponent.vue --> <script setup> const first = defineModel('first') const last = defineModel('last') </script> <template> <input v-model="first" placeholder="Имя" /> <input v-model="last" placeholder="Фамилия" /> </template><!-- App.vue --> <ChildComponent v-model:first="name" v-model:last="surname" />Пояснение: удобно, когда компонент управляет несколькими значениями (например, фильтрами, диапазонами, формами).
3. Наследование атрибутов: концепция “fall-through”
Что такое “fall-through” атрибуты
Как Vue автоматически передаёт неиспользованные атрибуты дочернему элементу
Пример:
<BaseButton class="btn-primary" id="save-btn"> Сохранить </BaseButton><!-- BaseButton.vue --> <template> <!-- class и id автоматически "провалятся" сюда --> <button><slot /></button> </template>Как отключить поведение:
<script setup> defineOptions({ inheritAttrs: false }) </script> <template> <!-- теперь нужно явно передавать $attrs --> <button v-bind="$attrs"><slot /></button> </template>Пояснение: “fall-through” делает компоненты гибче, но важно понимать, когда им управлять вручную — например, если нужно фильтровать атрибуты.
💡 Итог
Теперь вы знаете:
как строить гибкие компоненты через слоты,
как реализовывать двустороннюю связь данных с помощью
v-modelиdefineModel,как управлять атрибутами и их наследованием, избегая неожиданных побочных эффектов.
Vue3.ru