Skip to content

Atributos de Passagem

Neste material assume-se conhecimento dos Fundamentos dos Componentes. Precisamos entender o básico de componentes para acompanhar este material.

Herança de Atributo

Um "atributo de passagem" é um atributo ou ouvinte de evento de v-on que é passado a um componente, mas não é explicitamente declarado nas propriedades ou emissões do componente recetor. Os exemplos comuns disto incluem os atributos class, style, e id.

Quando um componente desenhar um único elemento de raiz, os atributos de passagem serão automaticamente adicionados aos atributos do elemento de raiz. Por exemplo, dado um componente <MyButton> com o seguinte modelo de marcação:

template
<!-- modelo de marcação do <MyButton> -->
<button>click me</button>

E um pai que utiliza este componente com:

template
<MyButton class="large" />

O modelo de objeto do documento (DOM) resultante seria:

html
<button class="large">click me</button>

Neste exemplo, <MyButton> não declarou class como uma propriedade aceita. Portanto, class é tratado como um atributo de passagem e automaticamente adicionado ao elemento de raiz do <MyButton>.

Fusão de class e style

Se o elemento de raiz do componente filho já tiver atributos class ou style existentes, este será fundido com os valores de class e style que serão herdados do pai. Suponhamos que alteramos o modelo de marcação do <MyButton> no exemplo anterior para:

template
<!-- modelo de marcação do <MyButton> -->
<button class="btn">click me</button>

Então, o modelo de objeto do documento (DOM) resultante tornar-se-ia agora:

html
<button class="btn large">click me</button>

Herança de Ouvinte de v-on

A mesma regra se aplica aos ouvintes de eventos de v-on:

template
<MyButton @click="onClick" />

O ouvinte de click será adicionado ao elemento de raiz do <MyButton>, ou seja, o elemento nativo <button>. Quando o <button> nativo for clicado, acionará o método onClick do componente pai. Se o <button> nativo já tiver um ouvinte de click vinculado com v-on, então ambos os ouvintes serão acionados.

Herança de Componente Encaixado

Se um componente desenhar outro componente como seu nó de raiz, por exemplo, nós refizemos <MyButton> para desenhar um <BaseButton> como sua raiz:

template
<!-- modelo de marcação do <MyButton/> que simplesmente desenha um outro componente -->
<BaseButton />

Então os atributos de passagem recebidos por <MyButton> serão automaticamente encaminhados ao <BaseButton>.

Nota que:

  1. Os atributos encaminhados não incluem quaisquer atributos que são declarados como propriedades, ou ouvintes de v-on de eventos declarados por <MyButton> - em outras palavras, as propriedades e os ouvintes declarados foram "consumidos" por <MyButton>.

  2. Os atributos encaminhados podem ser aceites como propriedades por <BaseButton>, se declarados por este.

Desativação da Herança de Atributo

Se não quisermos que um componente herde automaticamente os atributos, podemos definir inheritAttrs: false nas opções do componente.

Desde a versão 3.3 também podemos usar defineOptions diretamente em <script setup>:

vue
<script setup>
defineOptions({
  inheritAttrs: false
})
// ...lógica de configuração
</script>

O cenário comum para desativar a herança de atributo é quando os atributos precisam ser aplicados a outros elementos além do nó de raiz. Ao definir a opção inheritAttrs como false, podemos ter total controlo sobre onde os atributos de passagem devem ser aplicados.

Estes atributos de passagem podem ser acessados diretamente em expressões de modelo de marcação como $attrs:

template
<span>Fallthrough attributes: {{ $attrs }}</span>

O objeto $attrs inclui todos os atributos que não são declarados pelas opções props ou emits do componente (por exemplo, class, style, ouvintes de v-on, etc.).

Algumas notas:

  • Ao contrário das propriedades, os atributos de passagem preservam a sua caixa de texto original na JavaScript, por isto um atributo como foo-bar precisa de ser acessado como $attrs['foo-bar'].

  • Um ouvinte de evento de v-on como @click será exposto sobre o objeto como uma função sob a $attrs.onClick.

Usando o nosso exemplo do componente <MyButton> da secção anterior — por vezes podemos precisar de envolver o verdadeiro elemento <button> com um <div> adicional para fins de estilização:

template
<div class="btn-wrapper">
  <button class="btn">click me</button>
</div>

Nós queremos que todos os atributos de passagem como class e ouvintes de v-on que sejam aplicados ao <button> interno, não ao <div> externo. Nós podemos alcançar isto com inheritAttrs: false e v-bind="$attrs":

template
<div class="btn-wrapper">
  <button class="btn" v-bind="$attrs">click me</button>
</div>

É preciso lembrar que v-bind sem um argumento vincula todas as propriedades dum objeto como atributos ao elemento de destino.

Herança de Atributo sobre Vários Nós de Raiz

Ao contrário dos componentes com um único nó de raiz, os componentes com vários nós de raiz não têm um comportamento automático de passagem de atributo. Se $attrs não estiver vinculado explicitamente, um aviso de execução será emitido:

template
<CustomLayout id="custom-layout" @click="changeValue" />

Se <CustomLayout> tiver o seguinte modelo de marcação com várias raízes, haverá um aviso porque a Vue não pode ter a certeza de onde aplicar os atributos de passagem:

template
<header>...</header>
<main>...</main>
<footer>...</footer>

O aviso será suprimido se $attrs for explicitamente vinculado:

template
<header>...</header>
<main v-bind="$attrs">...</main>
<footer>...</footer>

Acesso aos Atributos de Passagem na JavaScript

Se necessário, podemos acessar os atributos de passagem dum componente no <script setup> usando a interface de programação useAttrs():

vue
<script setup>
import { useAttrs } from 'vue'

const attrs = useAttrs()
</script>

Se não estivermos usando o <script setup>, attrs será exposta como uma propriedade de contexto de setup():

js
export default {
  setup(props, ctx) {
    // os atributos de passagem são
    // expostos como `ctx.attrs`
    console.log(ctx.attrs)
  }
}

Nota que, embora o objeto attrs reflita sempre os últimos atributos de passagem, não é reativo (por razões de desempenho). Nós podemos usar observadores para observar as suas alterações. Se precisamos de reatividade, usamos uma propriedade. Alternativamente, podemos usar onUpdated() para executar efeitos colaterais com as attrs mais recentes em cada atualização.

Se necessário, podemos acessar os atributos de passagem dum componente através da propriedade de instância $attrs:

js
export default {
  created() {
    console.log(this.$attrs)
  }
}
Atributos de Passagem has loaded