Skip to content

Передача обычных атрибутов

Подразумевается, что вы уже изучили и разобрались с разделом Основы компонентов. Если нет — прочитайте его сначала.

Наследование атрибутов

Обычный атрибут для компонента — атрибут или слушатель события 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>.

Обратите внимание на то, что:

  1. Передаваемые атрибуты не включают атрибуты, которые объявлены как входные параметры или v-on слушатели объявленных событий <MyButton> - другими словами, объявленные входные параметры и слушатели были "поглощены" <MyButton>.

  2. Переданные атрибуты могут быть приняты <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 при каждом обновлении.

При необходимости вы можете получить доступ к обычным атрибутам компонента через свойство экземпляра $attrs:

js
export default {
  created() {
    console.log(this.$attrs)
  }
}
Передача обычных атрибутовУже загружено