Skip to content

透传 Attributes

Attribute 继承

透传 Attributes 是指父组件传递给子组件的属性,但不被子组件声明为 propemits 的属性。这些属性会自动传递给子组件的根元素。

html
<MyButton class="large" />
html
<!-- <MyButton> 的模板 -->
<button>Click Me</button>

最终渲染的结果为

html
<button class="large">Click Me</button>

这里MyButton没有将class声明为一个prop,所以class被是为透传 Attributes,自动透传到了MyButton的根元素button上。

classstyle的合并

如果一个子组件的根元素已经有了classstyle,那么透传的classstyle会被合并到根元素上。

html
<MyButton class="large" />

渲染结果为

html
<button class="large large">Click Me</button>

v-on监听器继承

同样的合并规则也适用与v-on监听器。

html
<MyButton v-on:click="onClick" />

渲染结果为

html
<button v-on:click="onClick">Click Me</button>

深层组件继承

有些情况下,一个组件会在根节点上渲染另一个组件,比如我们重构以西啊MyButton,让它在根节点上渲染一个BaseButton

html
<!-- <MyButton/> 的模板,只是渲染另一个组件 -->
<BaseButton />

此时 ,MyButton接收的透传 Attributes 会传递给BaseButton

注意

  • 透传的 attribute 不会包含<MyButton>组件上声明的propemits。也就是说,只有当propemits没有声明时,透传的 attribute 才会被传递。
  • 透传的 attribute 若符合声明,也可以作为props传入<BaseButton>

禁用 Attribute 继承

有些情况下,你可能不希望组件的根元素继承 attribute。在这种情况下,你可以使用inheritAttrs: false选项。

javascript
// Vue2
export default {
  inheritAttrs: false,
  props: ['label'],
  created() {
    console.log(this.$attrs) // 访问非prop属性
  }
}
// Vue3.3+
<script setup>
    defineOptions({
    inheritAttrs: false
})
    // ...setup 逻辑
</script>

Vue3.2- 结合普通script

javascript

<script>
    export default {
    inheritAttrs: false // 传统选项式写法
}
</script>

<script setup>
    // 组合式 API 逻辑
</script>

Vue3.2- 通过 export default 包装(适合简单场景)

javascript
<script setup>
const __setup__ = {
  inheritAttrs: false,
  // 其他选项...
}

export default __setup__
</script>

最常见的需要禁用透传的场景就是 attribute需要应用在根节点以外的其他元素上.通过设置inherAttrsfalse,你可以手动指定哪些 attribute 应该被添加到根节点以外的元素上。

这些透传过来的 attribute 可以通过$attrs对象访问。$attrs是一个响应式对象,包含了除组件所声明的propsemits之外的所有透传的 attribute。你可以使用v-bind指令将$attrs绑定到其他元素上。

html
<ChildComponent v-bind="$attrs" />

注意:

  • 透传的attribute保留了大小写,需要访问时需要注意($attrs['foo-bar']而不是$attrs['fooBar'])
  • @click这样的监听器事件将会作为$attrs对象的一个函数暴露($attrs.onClick)
html
<div class="btn-wrapper">
  <button class="btn" v-bind="$attrs">Click Me</button>
</div>
<script setup>
  defineOptions({
    inheritAttrs: false,
  })
  // ...
</script>

多根节点的 Attribute 继承

有着多根节点的组件没有自动 attribute 继承行为。如果需要将 attribute 应用到多个根节点上,你可以使用v-bind="$attrs"显式绑定。否则会抛出一个运行时警告

html
<CustomLayout id="custom-layout" @click="changeValue" />
html
<!-- CustomLayout.vue -->
<header>...</header>
<main>...</main>
<footer>...</footer>

显式绑定

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

JavaScript中访问透传 Attributes

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

  const attrs = useAttrs()
</script>

<script>
  export default {
    setup(props, ctx) {
      // 透传 attribute 被暴露为 ctx.attrs
      console.log(ctx.attrs)
    },
  }
</script>

<!-- Vue2 -->
<script>
  export default {
    inheritAttrs: false,
    created() {
      console.log(this.$attrs) // 访问非prop属性
    },
  }
</script>

注意: 在没有使用<script setup>的情况下,虽然attrs对象总是反映为最新的透传 attribute,,但它不是响应式的,不可以通过侦听器去监听他的变化, 如果需要响应性,可以使用prop或者可也可以使用onUpdated()使每次更新的时候结合最新的attrs执行副作用