Программирование HTML Vue defineProps Mon, January 26 2026  

Поделиться

Нашли опечатку?

Пожалуйста, сообщите об этом - просто выделите ошибочное слово или фразу и нажмите Shift Enter.


Vue defineProps Печать
Добавил(а) microsin   

defineProps() это макрос компилятора во Vue 3 Composition API (вставляется в < script setup>), который используется для объявления входных параметров (props) компонента [2]. С помощью параметров можно более гибко переиспользовать один и тот же компонент, модифицируя его внешний вид и поведение.

Пример простого компонента, отображающего название и значение какого-нибудь параметра:

// Файл компонента Stat.vue:
< script setup>
const { label, stat } = defineProps(['label', 'stat']) < /script>
< template> < div class="stat"> < div class="stat-name">{{ label }}< /div> < div class="stat-value">{{ stat }}< /div> < /div> < /template>
< style scoped> .stat {
font-size: 28px;
display: flex;
justify-content: space-between;
gap: 16px; } .stat-name {
font-weight: 700; } .stat-value {
font-weight: 500; } < /style>

Здесь label и stat заданы в виде массива свойств (properties, или сокращенно props), с помощью которых в компоненте приложения App.vue их можно использовать с разными значениями:

// Файл компонента приложения App.vue:
< script setup>
import Stat from "./components/Stat.vue" < /script>
< template> < main class="main"> < Stat label="Влажность" stat="90%" /> < Stat label="Осадки" stat="0%" /> < /main> < /template>
< style scoped> .main {
background: var(--color-bg-main);
padding: 60px 50px;
border-radius: 25px; } < /style>

Пропсы можно определять как объекты:

// Stat.vue
< script setup>
//const { label, stat } = defineProps(['label', 'stat'])
const { label, stat } = defineProps({
label: String,
stat: String }) < /script>

Можно задать значения по умолчанию для props. Например:

// Stat.vue
< script setup>
const { label = "Не задан", stat } = defineProps({
label: String,
stat: String }) < /script>

В этом случае если при использовании компонента Stat не было задано свойство label, то оно автоматически будет присвоено значением по умолчанию.

Более громоздкий вариант для задания значений по умолчанию в JavaScript работает через withDefaults. Он использовался для кода Vue версии 3.5 и ниже. Тот же самый пример с помощью withDefaults:

// Stat.vue
< script setup>
const props = withDefaults (
defineProps({
label: String,
stat: String
}),
{
label: = "Не задан",
} ); < /script>
< template> < div class="stat"> < div class="stat-name">{{ props.label }}< /div> < div class="stat-value">{{ props.stat }}< /div> < /div> < /template>

В этом случае props нельзя деструктурировать, потому что они теряют реактивность. Т. е. так делать не надо:

// Stat.vue
< script setup>
const { label, stat } = withDefaults (
defineProps({
label: String,
stat: String
}),
{
label: = "Не задан",
} ); < /script>
< template> < div class="stat"> < div class="stat-name">{{ label }}< /div> < div class="stat-value">{{ stat }}< /div> < /div> < /template>

[Передача props через переменные]

Примере выше приложение App.vue передает в дочерний компонент Stat.vue захардкоженные данные. Однако есть возможность передавать динамический контент в виде переменных с помощью атрибута 'v-bind', или ':'. Например:

< script setup>
import Stat from "./components/Stat.vue"
const label = "Влажность"
const stat = "90%" < /script>
< template> < main class="main"> < Stat v-bind:label="label" v-bind:stat="stat" /> < Stat label="Осадки" stat="0%" /> < /main> < /template>

Сокращенная запись, v-bind заменяется двоеточием:

    < Stat :label="label" :stat="stat" />

С помощью такого способа задавать значения в дочернем компоненте мы получаем важное преимущество: значения можно изменять динамически, например запросить у пользователя ввод определенного значения.

Директиву v-bind можно использовать также с объектами, например вот так мы можем передать объект целиком:

< script setup>
import Stat from "./components/Stat.vue"
const myobj = {
label: "Влажность",
stat: "90%"
} < /script>
< template> < main class="main"> < Stat v-bind="myobj" /> < Stat label="Осадки" stat="0%" /> < /main> < /template>

[Основной синтаксис]

В JavaScript есть два основных способа объявления props:

Способ 1: Объектный синтаксис (наиболее распространенный)

< script setup>
const props = defineProps({
// 1. Простая проверка типа
title: String,

// 2. Несколько допустимых типов
userId: [String, Number],

// 3. Подробная конфигурация
count: {
type: Number,
default: 0,
required: false,
validator: (value) => value >= 0 && value < = 100
},

// 4. Объекты и массивы со значениями по умолчанию
user: {
type: Object,
default: () => ({ name: 'Гость', age: null })
},

// 5. Функции как props
onSubmit: Function,

// 6. Кастомный класс
date: Date }) < /script>

Способ 2: Синтаксис с массивом строк (упрощенный)

< script setup>
// Только имена props без проверки типов
const props = defineProps(['title', 'count', 'items']) < /script>
< template> < div>{{ title }} - {{ count }}< /div> < /template>

Детали каждой опции:

type — проверка типа данных

< script setup>
const props = defineProps({
// Все доступные встроенные типы:
name: String,
age: Number,
isActive: Boolean,
hobbies: Array,
config: Object,
birthDate: Date,
onUpdate: Function,
customInstance: CustomClass, // ваш собственный класс

// Или комбинация типов:
id: [String, Number, Symbol],

// Типы с конструкторами:
items: {
type: Array, default: () => []
} }) < /script>

default — значение по умолчанию

< script setup>
const props = defineProps({
// Примитивные типы
count: {
type: Number,
default: 10
},

// Строки
message: {
type: String,
default: 'Привет, мир!'
},

// Булевы значения
isVisible: {
type: Boolean,
default: true
},

// ⚠️ ВАЖНО: Для объектов и массивов используйте функцию!
// ❌ Неправильно: // user: { type: Object, default: {} }
// ✅ Правильно:
user: {
type: Object,
default: () => ({ name: 'Аноним', role: 'user' })
},

items: {
type: Array,
default: () => []
},

// Функции по умолчанию
filterFn: {
type: Function,
default: () => (item) => true
} }) < /script>

required — обязательный параметр

< script setup>
const props = defineProps({
// Обязательный параметр без значения по умолчанию
userId: {
type: String,
required: true
},

// Можно комбинировать required с default
theme: {
type: String,
required: true,
default: 'light' // будет использоваться, если parent не передан prop
} }) < /script>

validator — кастомная (пользовательская) валидация

< script setup>
const props = defineProps({
// Простая валидация
age: {
type: Number,
validator: (value) => value >= 0 && value < = 120
},

// Валидация строки
status: {
type: String,
validator: (value) => ['active', 'inactive', 'pending'].includes(value)
},

// Валидация с параметром prop
password: {
type: String,
validator: (value) => {
// Проверка сложности пароля
if (value.length < 8) return false
if (!/[A-Z]/.test(value)) return false
if (!/[0-9]/.test(value)) return false
return true
}
},

// Валидация, зависящая от другого prop (нужен computed или watch)
endDate: {
    type: Date,
validator: function(value) {
// this не работает в стрелочных функциях!
return value > this.startDate
}
} }) < /script>

[Работа с props в компоненте]

Доступ к props:

< script setup>
const props = defineProps({
title: String,
count: Number,
items: Array })

// Использование в JavaScript console.log(props.title) console.log(props.count) console.log(props.items.length)

// Props реактивны - можно использовать в watch
import { watch } from 'vue'
watch(() => props.count, (newVal, oldVal) => {
console.log(`Count изменился с ${oldVal} на ${newVal}`) })

// Props в computed свойствах
import { computed } from 'vue'

const doubledCount = computed(() => props.count * 2) < /script>
< template> < !-- Использование в шаблоне --> < div>{{ title }}< /div> < div v-for="item in items" :key="item.id"> {{ item.name }} < /div> < /template>

Преобразование имен (camelCase → kebab-case)

< !-- ChildComponent.vue -->
< script setup>
const props = defineProps({
userName: String, // camelCase в JS
itemCount: Number, // camelCase в JS
isDialogVisible: Boolean }) < /script>
< !-- ParentComponent.vue --> < template> < !-- Используйте kebab-case в шаблоне --> < child-component user-name="Иван" :item-count="5" :is-dialog-visible="true" /> < /template>

[Особые случаи]

Передача всех props дочернему элементу:

< script setup>
const props = defineProps({
id: String,
class: String,
title: String,
// ... другие props }) < /script>
< template> < !-- Автоматическое связывание всех props --> < div v-bind="props"> {{ title }} < /div> < !-- Или выборочно --> < child-component v-bind="props" /> < /template>

Props с динамическими именами:

< script setup>
const props = defineProps({
// Динамические props через вычисляемое имя
['custom' + 'Prop']: String, // вычисляемое имя свойства

// Но обычно так не делают - лучше использовать статические имена }) < /script>

Вложенная проверка объектов:

< script setup>
const props = defineProps({
// Для сложных структур используйте кастомный валидатор
config: {
type: Object,
default: () => ({}),
validator: (value) => {
// Проверка структуры объекта
if (!value.theme) return false
if (!['light', 'dark'].includes(value.theme)) return false
if (typeof value.autoSave !== 'boolean') return false
return true
}
} }) < /script>

[Распространенные ошибки]

1. Не деструктурируйте props напрямую:

< script setup>
const props = defineProps({ title: String, count: Number })

// ❌ Плохо - потеря реактивности
const { title, count } = props

// ✅ Хорошо - сохраняйте ссылку на props console.log(props.title)

// ✅ Альтернатива с toRefs
import { toRefs } from 'vue'
const { title, count } = toRefs(props)
// Теперь title и count реактивны! < /script>

2. Не мутируйте props:

< script setup>
const props = defineProps({ items: Array })

// ❌ Плохо - мутация props props.items.push('новый элемент')

// ✅ Хорошо - создайте локальную копию
import { ref, watch } from 'vue'
const localItems = ref([])
watch(() => props.items, (newItems) => {
localItems.value = [...newItems] }, { immediate: true }) < /script>

3. Правильные значения по умолчанию:

< script setup>
const props = defineProps({
// ❌ Неправильно для объектов/массивов
user: { type: Object, default: {} },
items: { type: Array, default: [] },

// ✅ Правильно - используйте функцию
user: { type: Object, default: () => ({}) },
items: { type: Array, default: () => [] } }) < /script>

[Полезные шаблоны]

Прокси для всех props:

< script setup>
// Принимаем все props родителя
const props = defineProps({
// Можно перечислить все возможные HTML атрибуты
id: String,
class: String,
style: [String, Object, Array],
title: String,
disabled: Boolean,
// ... и т.д. })

// Или использовать пустое объявление для принятия любых props
const props = defineProps({}) < /script>
< template> < div v-bind="$attrs"> < !-- Содержимое --> < /div> < /template>

Props с вычисляемыми значениями:

< script setup>
import { computed } from 'vue'
const props = defineProps({ price: Number, currency: {
type: String,
default: 'USD'
} })

// Вычисляемое значение на основе props
const formattedPrice = computed(() => {
return new Intl.NumberFormat('ru-RU', {
style: 'currency',
currency: props.currency
}).format(props.price) }) < /script>

Комбинированные props:

< script setup>
const props = defineProps({
// Базовые props modelValue: {
type: [String, Number, Boolean, Array, Object],
default: null
},

// Конфигурационные props
options: {
type: Object,
default: () => ({})
},

// Состояния
disabled: Boolean,
readonly: Boolean,

// Валидация rules: {
type: Array,
default: () => []
} }) < /script>

[Отладка и проверка]

< script setup>
const props = defineProps({
title: String,
count: Number })

// Вывод props в консоль при изменении
import { watch } from 'vue'
import { useDevtools } from '@vue/devtools-api'
watch(props, (newProps) => {
console.log('Props обновились:', newProps)

// Интеграция с Vue DevTools
if (process.env.NODE_ENV === 'development') {
const devtools = useDevtools()
devtools.inspect(props)
} }, { deep: true, immediate: true }) < /script>

[Полный пример компонента]

< script setup>
import { computed, watch } from 'vue'

// Объявление всех props
const props = defineProps({
// Идентификаторы
id: String, name: {
type: String,
required: true
},

// Состояния isActive: {
type: Boolean,
default: false
},
isLoading: {
type: Boolean,
default: false
},
isDisabled: Boolean,

// Данные
value: {
type: [String, Number, Boolean, Array, Object],
default: null
},
items: {
type: Array,
default: () => []
},

// Конфигурация
settings: {
type: Object,
default: () => ({
maxItems: 10,
sortable: true,
filterable: false
}),
validator: (value) => {
return value.maxItems > 0 && typeof value.sortable === 'boolean'
}
},

// События
onChange: Function,
onSelect: Function })

// Реактивные вычисления на основе props
const itemCount = computed(() => props.items.length)
const isMaxReached = computed(() => itemCount.value >= props.settings.maxItems)

// Отслеживание изменений props watch(() => props.isActive, (newVal) => {
if (newVal && props.onChange) {
props.onChange('activated')
} })

// Локальное состояние на основе props
const localValue = ref(props.value)
watch(() => props.value, (newVal) => {
localValue.value = newVal }) < /script>
< template> < div :id="id" :class="[
'component',
{
'is-active': isActive,
'is-loading': isLoading,
'is-disabled': isDisabled || isMaxReached
}
]" > < h3>{{ name }}< /h3> < p>Элементов: {{ itemCount }} / {{ settings.maxItems }}< /p> < ul v-if="!isLoading"> < li v-for="(item, index) in items" :key="index" @click="onSelect && onSelect(item)" > {{ item }} < /li> < /ul> < div v-else>Загрузка...< /div> < /div> < /template>
< style scoped> .component {
border: 1px solid #ccc; padding: 1rem; }
.is-active {
border-color: blue; }
.is-disabled {
opacity: 0.5; pointer-events: none; } < /style>

Итог: defineProps() в JavaScript предоставляет мощную, но гибкую систему типизации и валидации props. Ключевые моменты:

1. Используйте функции для значений по умолчания объектов и массивов.
2. Не мутируйте props напрямую.
3. Не деструктурируйте props без toRefs.
4. Используйте валидаторы для сложных проверок.
5. Помните о преобразовании имен из camelCase в kebab-case.

[Основное использование (JavaScript)]

< script setup>
// Объявление props
const props = defineProps({
title: String,
count: {
type: Number,
default: 0,
required: false,
validator: (value) => value >= 0
},
items: {
type: Array,
default: () => []
} })

// Использование props console.log(props.title) < /script>

[Синтаксис с TypeScript]

Более предпочтительный способ с TypeScript:

< script setup lang="ts">
// Интерфейс props
interface Props {
title: string count?: number items: string[]
status?: 'active' | 'inactive' }

// Объявление с интерфейсом
const props = defineProps< Props>()

// Со значениями по умолчанию
const props = withDefaults(defineProps< Props>(), {
count: 0, items: () => [],
status: 'active' }) < /script>

[Основные опции]

Каждый prop может иметь:

type — тип данных (String, Number, Boolean, Array, Object, Date, Function или кастомный класс)
default — значение по умолчанию (для объектов/массивов используйте функцию)
required — обязательный параметр
validator — функция-валидатор

Особенности:

1. Макрос компилятора — defineProps() обрабатывается на этапе компиляции и удаляется из итогового кода.
2. Доступность в шаблоне — объявленные props автоматически доступны в шаблоне.
3. Только чтение — props являются реактивными, но неизменяемыми.
4. Нет необходимости импортировать — доступен глобально в < script setup>.

[Пример с валидацией]

< script setup>
const props = defineProps({
// Простая проверка типа
name: String,

// Несколько допустимых типов
value: [String, Number],

// С подробной конфигурацией
rating: {
type: Number,
required: true,
validator: (value) => value >= 1 && value < = 5
},

// Объект с умолчанием
config: {
type: Object,
default: () => ({
color: 'blue',
size: 'medium'
})
} }) < /script>

[Отличие от Options API]

Composition API (`< script setup>`):

< script setup>
const props = defineProps({ ... }) < /script>

Options API:

< script>
export default {
props: { ... } } < /script>

Важные моменты:

1. Не деструктурируйте props без toRefs — потеряется реактивность:

< script setup>
// ❌ Плохо - потеря реактивности
const { title } = defineProps()

// ✅ Хорошо - сохраняется реактивность
const props = defineProps()
const title = toRef(props, 'title') < /script>

2. Используйте withDefaults для TypeScript при необходимости иметь значения по умолчанию.

3. Имена в camelCase при объявлении автоматически преобразуются в kebab-case в шаблоне.

defineProps() — это типобезопасный, лаконичный способ объявления props, который особенно удобен при использовании TypeScript и Composition API.

[Ссылки]

1. Vue 3, быстрый старт.
2. Vue: концепция компонентов.
3. Директивы шаблона Vue.

 

Добавить комментарий


Защитный код
Обновить

Top of Page