Skip to content

透传 Attributes 的“透传”意味着属性和属性修饰符从一个组件传递到另一个组件,而不需要显式地(通过 defineXXX 声明)在每个组件中重新声明或处理它们,比如 classstyle 和 id

html
<MyButton class="large" />
-->不需要显式声明直接渲染到DOM上的结果:
<button class="large">Click Me</button>

attributes 合并

class 和 style

如果该元素本身具有 classstyle 属性,那么透传属性会与之合并,前文已经提及。

v-on 监听器继承

在父组件引入子组件标签上声明一个 v-on

html
<MyButton @click="onClick" />
事件冒泡

事件处理的顺序是基于事件冒泡机制的。事件首先从目标元素触发,然后冒泡到其父元素,直到到达根元素。因此,如果你在子组件内的某个子元素(例如按钮)上添加了事件监听器,这个监听器会在根元素的监听器之后被触发。 也就是说,一个标签优先响应自身的监听器,然后再逐级响应继承来的监听器。

深层组件继承

父传子的属性,例如 props 或是针对 emits 声明事件的 v-on 侦听函数,经过一层传递即被截留,其余符合要求的 attributes 才会被继续向下传递。 对于 props,如果在一层中没有被 defineProps 声明,会被透传到下一层,emit 事件同理。

禁用继承

该选项控制根组件是否继承父组件的属性:

ts
defineOptions({ inheritAttrs: false })

不禁用属性继承的话,本组件中所有声明的 props 都会被应用到根元素上,此时如果在非根元素上想要使用 props 属性,会被根元素截留,因此要禁用自动继承而根据内部标签定义的 props 手动管理继承。

html
<template>
  <button>
    <span class="icon" :class="iconClass"></span>
    <slot></slot>
  </button>
</template>

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

const iconClass = ref('')

defineOptions({
	inheritAttrs: false
})
const disabled = false
</script>

还有一种情况,将一些标签放入一个 div 容器中,如果不禁用继承就无法将相应属性传递给子组件。

访问透传属性

$attrs 包括了所有除已声明的 props 和 emits 以外的所有父组件传递的属性。

  • 例如 classstylev-on 监听器。

多根节点的 Attributes 继承

首先明确,透传传的其实就是 $attrs 多根节点不会触发自动属性透传,因为不确定把它加到哪个组件上去,此时应当显式声明,否则会触发一个警告:

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

在 JS 中访问 Attribute

$attrs 可以直接在 template 中调用,如果要在 script 中访问则需要使用 useAttrs 声明:

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

const attrs = useAttrs()
console.log(attrs.name)
</script>