Реквізити
Ця сторінка передбачає, що ви вже прочитали основи компонентів. Прочитайте це спочатку, якщо ви новачок у компонентах.
Оголошення реквізитів
Компоненти Vue вимагають явного оголошення реквізитів, щоб Vue знав, які зовнішні реквізити, передані компоненту, слід розглядати як прохідні атрибути (що буде обговорюватися в цьому спеціальному розділі).
У SFC, які використовують <script setup>
, реквізити можна оголошувати за допомогою defineProps()
:
vue
<script setup>
const props = defineProps(['foo'])
console.log(props.foo)
</script>
У компонентах без <script setup>
, реквізити оголошуються за допомогою параметра props
:
js
export default {
props: ['foo'],
setup(props) {
// setup() отримує реквізити як перший аргумент.
console.log(props.foo)
}
}
Зауважте, що аргумент, переданий у defineProps()
, такий самий, як значення, надане параметрам props
: той самий API параметрів реквізитів використовується двома стилями оголошення.
На додаток до оголошення реквізитів за допомогою масиву рядкових величин, ми також можемо використовувати об’єктний синтаксис:
js
// З <script setup>
defineProps({
title: String,
likes: Number
})
js
// Без <script setup>
export default {
props: {
title: String,
likes: Number
}
}
Для кожної властивості в синтаксисі оголошення об’єкта, ключ — це ім’я реквізиту, тоді як значення має бути функцією-конструктором очікуваного типу.
Це не лише документує ваш компонент, але й попередить інших розробників, які використовують ваш компонент у консолі браузера, якщо вони передають неправильний тип. Ми обговоримо додаткові відомості про перевірку реквізитів далі на цій сторінці.
Якщо ви використовуєте TypeScript із <script setup>
, можна також оголосити реквізити за допомогою суто анотацій типу:
vue
<script setup lang="ts">
defineProps<{
title?: string
likes?: number
}>()
</script>
Детальніше: типізація реквізитів компонента
Деталі передачі реквізиту
Регістр імені реквізиту
Ми оголошуємо довгі імена реквізитів за допомогою camelCase, оскільки це дозволяє уникнути необхідності використовувати лапки під час використання їх як ключів властивостей і дозволяє нам посилатися на них безпосередньо у виразах шаблону, бо вони є дійсними ідентифікаторами JavaScript:
js
defineProps({
greetingMessage: String
})
template
<span>{{ greetingMessage }}</span>
Технічно ви також можете використовувати camelCase під час передачі реквізитів дочірньому компоненту (за винятком шаблонів DOM). Однак, угода передбачає використання kebab-case у всіх випадках для узгодження з атрибутами HTML:
template
<MyComponent greeting-message="привіт" />
Ми використовуємо PascalCase для тегів компонентів, коли це можливо, оскільки це покращує читабельність шаблону, відрізняючи компоненти Vue від нативних елементів. Однак використання camelCase під час передачі реквізитів не має такої практичної користі, тому ми вирішуємо дотримуватись конвенцій кожної мови.
Статичні реквізити проти динамічних реквізитів
Наразі ви бачили реквізити, що передавалися як статичні значення, наприклад:
template
<BlogPost title="Моя подорож з Vue" />
Ви також бачили реквізити, призначені динамічно за допомогою v-bind
або його скорочення :
, наприклад:
template
<!-- Динамічне присвоєння значення змінної -->
<BlogPost :title="post.title" />
<!-- Динамічне присвоєння значення складного виразу -->
<BlogPost :title="post.title + ' by ' + post.author.name" />
Передача значень різних типів
У двох наведених вище прикладах ми передаємо рядкові значення, але значення будь-якого типу може бути передане реквізиту.
Число
template
<!-- Незважаючи на те, що `42` є статичним, нам потрібен v-bind, щоб повідомити це Vue -->
<!-- це вираз JavaScript, а не рядок. -->
<BlogPost :likes="42" />
<!-- Динамічне присвоєння значення змінної. -->
<BlogPost :likes="post.likes" />
Логічний
template
<!-- Передача реквізиту без значення означатиме `true`. -->
<BlogPost is-published />
<!-- Незважаючи на те, що `false` є статичним, нам потрібен v-bind, щоб повідомити це Vue -->
<!-- це вираз JavaScript, а не рядок. -->
<BlogPost :is-published="false" />
<!-- Динамічне присвоєння значення змінної. -->
<BlogPost :is-published="post.isPublished" />
Масив
template
<!-- Незважаючи на те, що масив є статичним, нам потрібен v-bind, щоб повідомити це Vue -->
<!-- це вираз JavaScript, а не рядок. -->
<BlogPost :comment-ids="[234, 266, 273]" />
<!-- Динамічне присвоєння значення змінної. -->
<BlogPost :comment-ids="post.commentIds" />
Об’єкт
template
<!-- Незважаючи на те, що об’єкт є статичним, нам потрібен v-bind, щоб повідомити це Vue -->
<!-- це вираз JavaScript, а не рядок. -->
<BlogPost
:author="{
name: 'Вероніка',
company: 'Veridian Dynamics'
}"
/>
<!-- Динамічне присвоєння значення змінної. -->
<BlogPost :author="post.author" />
Прив'язка кількох реквізитів за допомогою об'єкта
Якщо ви хочете передати всі властивості об'єкта як реквізит, ви можете використовувати v-bind
без аргументу (v-bind
замість :prop-name
). Наприклад, задано об’єкт post
:
js
const post = {
id: 1,
title: 'Моя подорож з Vue'
}
Наступний шаблон:
template
<BlogPost v-bind="post" />
Буде еквівалентним до:
template
<BlogPost :id="post.id" :title="post.title" />
Односторонній потік даних
Всі реквізити формують односторонню зв’язку між дочірньою та батьківською властивостями: коли батьківська властивість оновлюється, вона переходить до дочірньої, але не навпаки. Це запобігає випадковій зміни стану батьківського компоненту дочірніми, що може ускладнити розуміння потоку даних вашої програми.
Крім того, щоразу, коли батьківський компонент оновлюється, усі атрибути в дочірньому компоненті оновлюватимуться останнім значенням. Це означає, що не слід намагатися змінити реквізит всередині дочірнього компонента. Якщо ви це зробите, Vue попередить вас у консолі:
js
const props = defineProps(['foo'])
// ❌ попередження, реквізити доступні лише для читання!
props.foo = 'bar'
Зазвичай є два випадки, коли виникає бажання змінити реквізит:
Реквізит використовується для передачі початкового значення; потім дочірній компонент хоче використовувати його як властивість локальних даних. У цьому випадку найкраще визначити властивість локальних даних, яка використовує реквізит як початкове значення:
jsconst props = defineProps(['initialCounter']) // counter використовує лише props.initialCounter як початкове значення; // його відключено від майбутніх оновлень реквізиту. const counter = ref(props.initialCounter)
Реквізит передається як необроблене значення, яке потрібно трансформувати. У цьому випадку найкраще визначити обчислювану властивість за допомогою значення реквізиту:
jsconst props = defineProps(['size']) // обчислювана властивість, яка автоматично оновлюється, коли реквізит змінюється const normalizedSize = computed(() => props.size.trim().toLowerCase())
Зміна реквізитів з типом об'єкту / масиву
Коли об'єкти та масиви передаються як реквізити, хоча дочірній компонент не може змінювати прив’язку реквізитів, він зможе змінити вкладені властивості об’єкта чи масиву. Це пов’язано з тим, що в JavaScript об’єкти та масиви передаються за посиланням, і для Vue необґрунтовано дорого запобігати таким мутаціям.
Основний недолік таких мутацій полягає в тому, що вони дозволяють дочірньому компоненту впливати на батьківський стан у спосіб, який не є очевидним для батьківського компонента, потенційно ускладнюючи потік даних у майбутньому. Як найкраща практика, ви повинні уникати таких мутацій, якщо тільки батько та дитина не тісно пов’язані задумом. У більшості випадків нащадок повинен випромінювати подію, щоб дозволити батькові виконати мутацію.
Перевірка реквізиту
Компоненти можуть вказувати вимоги до своїх реквізитів, наприклад типи, які ви вже бачили. Якщо вимога не виконується, Vue попередить вас у консолі JavaScript браузера. Це особливо корисно під час розробки компонента, призначеного для використання іншими.
Щоб указати перевірку реквізиту, ви можете надати об’єкт із вимогами перевірки для defineProps()
макроса замість масиву рядкових величин. Наприклад:
js
defineProps({
// Основна перевірка типу
// (`null` та `undefined` значення дозволять будь-який тип)
propA: Number,
// Кілька можливих типів
propB: [String, Number],
// Обов'язковий рядок
propC: {
type: String,
required: true
},
// Число зі значенням за промовчанням
propD: {
type: Number,
default: 100
},
// Об'єкт зі значенням за промовчанням
propE: {
type: Object,
// Значення за промовчанням для об’єктів або масивів мають бути повернуті
// фабричною функцією. Функція отримує необроблені реквізити,
// отримані компонентом як аргумент.
default(rawProps) {
return { message: 'Привіт' }
}
},
// Спеціальна функція перевірки
propF: {
validator(value) {
// Значення має відповідати одному з цих рядків
return ['успіх', 'увага', 'небезпека'].includes(value)
}
},
// Функція зі значенням за промовчанням
propG: {
type: Function,
// На відміну від об’єкта чи масиву за промовчанням, це не фабрика
// функція - це функція, яка слугуватиме значенням за промовчанням
default() {
return 'Функція за промовчанням'
}
}
})
TIP
Код всередині defineProps()
не може отримати доступ до інших змінних, оголошених з <script setup>
, оскільки весь вираз переміщується до зовнішньої область видимості функції під час компіляції.
Додаткова інформація:
Усі реквізити є необов’язковими за промовчанням, якщо не вказано
required: true
.Відсутній додатковий реквізит, відмінний від
Boolean
, матиме значенняundefined
.Відсутні атрибути
Boolean
будуть приведені доfalse
. Ви можете змінити це, встановивши для ньогоdefault
— тобто:default: undefined
, щоб поводитись як не-логічний реквізит.Якщо
default
(значення за промовчанням) вказано, воно використовуватиметься, якщо розв’язане значення реквізитуundefined
- це стосується як випадків, коли реквізит відсутній, так і передається явне значенняundefined
.
Коли перевірка реквізиту не вдасться, Vue видасть консольне попередження (якщо використовується збірка розробки).
Якщо використовуються Оголошення реквізитів на основі типу , Vue докладе всіх зусиль, щоб скомпілювати анотації типу в еквівалентні оголошення властивостей часу виконання. Наприклад, defineProps<{ msg: string }>
буде скомпільовано в { msg: { type: String, required: true }}
.
Перевірки типу виконання
type
може бути одним із таких нативних конструкторів:
String
Number
Boolean
Array
Object
Date
Function
Symbol
Крім того, type
також може бути спеціальним класом або функцією-конструктором, і твердження буде зроблено з перевіркою instanceof
. Наприклад, задано наступний клас:
js
class Person {
constructor(firstName, lastName) {
this.firstName = firstName
this.lastName = lastName
}
}
Ви можете використовувати його як тип реквізиту:
js
defineProps({
author: Person
})
Vue використовуватиме instanceof Person
, щоб перевірити, чи справді значення властивості author
є екземпляром класу Person
.
Логічна перевірка
Реквізити з типом Boolean
мають спеціальні правила приведення, щоб імітувати поведінку власних логічних атрибутів. Дано <MyComponent>
з таким оголошенням:
js
defineProps({
disabled: Boolean
})
Компонент можна використовувати таким чином:
template
<!-- еквівалент передачі :disabled="true" -->
<MyComponent disabled />
<!-- еквівалент передачі :disabled="false" -->
<MyComponent />
Якщо реквізит оголошено таким, що дозволяє використовувати декілька типів, також застосовуватимуться правила приведення для Boolean
. Однак існує перевага, коли дозволені і String
, і Boolean
- правило приведення Boolean застосовується, лише якщо Boolean з'являється перед String:
js
// disabled буде приведено до true
defineProps({
disabled: [Boolean, Number]
})
// disabled буде приведено до true
defineProps({
disabled: [Boolean, String]
})
// disabled буде приведено до true
defineProps({
disabled: [Number, Boolean]
})
// disabled буде проаналізовано як порожній рядок (disabled="")
defineProps({
disabled: [String, Boolean]
})