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

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

Обычный атрибут для компонента — атрибут или слушатель события, который передаётся в компонент, но не имеет соответствующего свойства указанного в props или emits. Частыми примерами подобного являются атрибуты class, style и id. Доступ к этим атрибутам можно получить через свойство $attrs.

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

Если в компоненте один корневой элемент, то обычные атрибуты будут добавляться к этому элементу автоматически. Например, для экземпляра компонента выбора даты:

app.component('date-picker', {
  template: `
    <div class="date-picker">
      <input type="datetime-local" />
    </div>
  `
})
1
2
3
4
5
6
7

Если потребуется определять статус компонента выбора даты через атрибут data-status, значение будет добавлено к корневому элементу (т.е. к div.date-picker).

<!-- Компонент выбора даты с обычным атрибутом -->
<date-picker data-status="activated"></date-picker>

<!-- Отрисованный компонент выбора даты -->
<div class="date-picker" data-status="activated">
  <input type="datetime-local" />
</div>
1
2
3
4
5
6
7

Аналогично правило применяется и для обработчиков событий:

<date-picker @change="submitChange"></date-picker>
1
app.component('date-picker', {
  created() {
    console.log(this.$attrs) // { onChange: () => {}  }
  }
})
1
2
3
4
5

Это удобно, когда корневым элементом компонента date-picker будет HTML-элемент, генерирующий событие change .

app.component('date-picker', {
  template: `
    <select>
      <option value="1">Вчера</option>
      <option value="2">Сегодня</option>
      <option value="3">Завтра</option>
    </select>
  `
})
1
2
3
4
5
6
7
8
9

Обработчик события change будет передан из родительского компонента в дочерний и станет вызываться при нативном событии change на корневом элементе <select>. При таком подходе не потребуется явно генерировать событие внутри date-picker:

<div id="date-picker" class="demo">
  <date-picker @change="showChange"></date-picker>
</div>
1
2
3
const app = Vue.createApp({
  methods: {
    showChange(event) {
      console.log(event.target.value) // выведет значение выбранного варианта
    }
  }
})
1
2
3
4
5
6
7

# Отключение наследования атрибутов

При необходимости отключить автоматическое наследование обычных атрибутов компонентом это можно сделать с помощью опции inheritAttrs: false.

Популярная причина, когда требуется отключать наследование атрибутов — необходимость добавления атрибутов на другой элемент вместо корневого.

Установив опцию inheritAttrs в false, добавлять атрибуты к выбранному элементу можно с помощью свойства $attrs, в нём будут все атрибуты, не указанные в свойствах props и emits (например, class, style, обработчики v-on, и т.д.).

Используя компонент для выбора дат из предыдущей главы, изменим добавление обычных атрибутов на элемент input, вместо корневого элемента div. Для этого воспользуемся сокращённой записью v-bind:


 


 




app.component('date-picker', {
  inheritAttrs: false,
  template: `
    <div class="date-picker">
      <input type="datetime-local" v-bind="$attrs" />
    </div>
  `
})
1
2
3
4
5
6
7
8

В таком случае обычный атрибут data-status будет добавляться на элемент input!

<!-- Компонент выбора даты с обычным атрибутом -->
<date-picker data-status="activated"></date-picker>

<!-- Отрисованный компонент выбора даты -->
<div class="date-picker">
  <input type="datetime-local" data-status="activated" />
</div>
1
2
3
4
5
6
7

# Наследование атрибутов при нескольких корневых элементах

В отличие от компонентов с одним корневым элементом, для компонентов с несколькими корневыми элементами не будет автоматического наследования атрибутов. Если $attrs не привязать к элементу явно, то это приведёт к предупреждению во время выполнения.

<custom-layout id="custom-layout" @click="changeValue"></custom-layout>
1
// НЕПРАВИЛЬНО, будет выведено предупреждение
app.component('custom-layout', {
  template: `
    <header>...</header>
    <main>...</main>
    <footer>...</footer>
  `
})

// ПРАВИЛЬНО, $attrs передаются на элемент <main>
app.component('custom-layout', {
  template: `
    <header>...</header>
    <main v-bind="$attrs">...</main>
    <footer>...</footer>
  `
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17