Передача обычных атрибутов
Подразумевается, что вы уже изучили и разобрались с разделом Основы компонентов. Если нет — прочитайте его сначала.
Наследование атрибутов
Обычный атрибут для компонента — атрибут или слушатель события v-on
, который передаётся в компонент, но не имеет соответствующего свойства в props или emits. Частыми примерами подобного являются атрибуты class
, style
, и id
.
Если в компоненте один корневой элемент, то обычные атрибуты будут добавляться к этому элементу автоматически. Например, есть компонент <MyButton>
со следующим шаблоном:
template
<!-- шаблон <MyButton> -->
<button>Нажми на меня</button>
И родитель, использующий этот компонент:
template
<MyButton class="large" />
Окончательный вариант DOM будет выглядеть так:
html
<button class="large">Нажми на меня</button>
В данном случае <MyButton>
не объявил class
в качестве принимаемого атрибута. Поэтому class
рассматривается как обычный атрибут и автоматически добавляется к корневому элементу <MyButton>
.
Объединение атрибутов class
и style
Если корневой элемент дочернего компонента уже имеет существующие атрибуты class
или style
, они будут объединены со значениями class
и style
, унаследованными от родителя. Предположим, мы изменим шаблон <MyButton>
в предыдущем примере на:
template
<!-- шаблон <MyButton> -->
<button class="btn">Нажми на меня</button>
Тогда окончательный DOM будет выглядеть так:
html
<button class="btn large">Нажми на меня</button>
Наследование слушателей v-on
То же правило применяется к слушателям событий v-on
:
template
<MyButton @click="onClick" />
Слушатель click
будет добавлен к корневому элементу <MyButton>
, то есть к собственному элементу <button>
. Когда нажата собственная кнопка <button>
, она вызовет метод onClick
родительского компонента. Если у нативной <button>
уже есть прослушиватель click
, связанный с v-on
, то сработают оба прослушивателя.
Наследование вложенных компонентов
Если компонент отображает другой компонент в качестве своего корневого узла, например, мы рефакторим <MyButton>
, чтобы отображать <BaseButton>
в качестве своего корня:
template
<!-- шаблон <MyButton/>, который просто отображает другой компонент -->
<BaseButton />
Тогда обычные атрибуты, полученные <MyButton>
будут автоматически переданы <BaseButton>
.
Обратите внимание на то, что:
Передаваемые атрибуты не включают атрибуты, которые объявлены как входные параметры или
v-on
слушатели объявленных событий<MyButton>
- другими словами, объявленные входные параметры и слушатели были "поглощены"<MyButton>
.Переданные атрибуты могут быть приняты
<BaseButton>
в качестве входных параметров, если они объявлены там.
Отключение наследования атрибутов
Если необходимо отключить автоматическое наследование атрибутов компонентом, то это можно сделать с помощью опции inheritAttrs: false
.
Начиная с версии 3.3, вы также можете использовать defineOptions
непосредственно в <script setup>
:
vue
<script setup>
defineOptions({
inheritAttrs: false
})
// ...логика настройки
</script>
Популярный сценарий, когда требуется отключать наследование атрибутов — необходимо добавлять атрибуты на другие элементы вместо корневого узла. Устанавливая опцию inheritAttrs
в значение false
, можно контролировать добавление атрибутов к другим элементам компонента.
Доступ к этим обычным атрибутам можно получить непосредственно в выражениях шаблона, как $attrs
:
template
<span>Обычные атрибуты: {{ $attrs }}</span>
Объект $attrs
включает все атрибуты, которые не объявлены в props
или emits
(например, class
, style
, v-on
слушатели и т.д.).
Некоторые примечания:
В отличие от входных параметров, обычные атрибуты сохраняют свой исходный регистр в JavaScript, поэтому к атрибуту типа
foo-bar
нужно обращаться как к$attrs['foo-bar']
.Слушатель события
v-on
, такой как@click
, будет отображаться на объекте в виде функции$attrs.onClick
.
Используя наш пример компонента <MyButton>
из предыдущего раздела, иногда нам может понадобиться обернуть элемент <button>
дополнительным <div>
для стилизации:
template
<div class="btn-wrapper">
<button class="btn">Нажми на меня</button>
</div>
Мы хотим, чтобы все обычные атрибуты, такие как class
и слушатели v-on
, применялись к внутреннему <button>
, а не к внешнему <div>
. Мы можем добиться этого с помощью inheritAttrs: false
и v-bind="$attrs"
:
template
<div class="btn-wrapper">
<button class="btn" v-bind="$attrs">Нажми на меня</button>
</div>
Помните, что v-bind
без аргумента связывает все свойства объекта как атрибуты целевого элемента.
Наследование атрибутов при нескольких корневых элементах
В отличие от компонентов с одним корневым элементом, для компонентов с несколькими корневыми элементами не будет автоматического наследования атрибутов. Если $attrs
не привязать к элементу явно, то это приведёт к предупреждению во время выполнения.
template
<CustomLayout id="custom-layout" @click="changeValue" />
Если <CustomLayout>
имеет следующий многокорневой шаблон, будет выдано предупреждение, поскольку Vue не может быть уверен, где применить обычные атрибуты:
template
<header>...</header>
<main>...</main>
<footer>...</footer>
Предупреждение будет подавлено, если $attrs
явно привязаны:
template
<header>...</header>
<main v-bind="$attrs">...</main>
<footer>...</footer>
Доступ к обычным атрибутам в JavaScript
При необходимости вы можете получить доступ к обычным атрибутам компонента в <script setup>
с помощью API useAttrs()
:
vue
<script setup>
import { useAttrs } from 'vue'
const attrs = useAttrs()
</script>
Если <script setup>
не используется, attrs
будет отображаться как свойство контекста setup()
:
js
export default {
setup(props, ctx) {
// обычные атрибуты отображаются как ctx.attrs
console.log(ctx.attrs)
}
}
Обратите внимание, что хотя объект attrs
здесь всегда отражает последние обычные атрибуты, он не является реактивным (по причинам производительности). Вы не можете использовать наблюдатели для наблюдения за его изменениями. Если вам нужна реактивность, используйте входной параметр. В качестве альтернативы вы можете использовать функцию onUpdated()
для выполнения побочных эффектов с последними attrs
при каждом обновлении.