vue3透传Attributes

612 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第26天,点击查看活动详情

写在前面

第一次听说透传Attributes这个词,是在我阅读vue3官方文档的时候,之前每次看到这类名词的时候,多多少少能猜到大概是个什么意思,但是当我看到这个词的时候我是一脸懵,透传Attributes是个什么玩意儿。于是便有了这篇文章。

透传Attributes

“透传 attribute”指的是传递给一个组件,却没有被该组件声明为 props或 emits 的 attribute 或者 v-on 事件监听器

通俗地理解就是父组件在调用子组件的时候,明明通过传值的操作给子组件传递属性,但是子组件却具有这个属性。比如常见的class, id, style。

class的透传

父组件给子组件传递一个class, 会绑定在子组件的容器元素上。如果一个子组件的根元素已经有了 class attribute,它会和从父组件上继承的值合并。

// 父组件
<HelloWorld class="hello-world" msg="Welcome to Your Vue.js App"/>

// 子组件
<template>
  <div class="test-wrapper">
    注入信息: {{location}}
    <button @click="updateLocation" v-preReClick>点我点我</button>
  </div>
</template>

最终渲染效果如下:

image.png

style的透传

style的效果和class一样,父组件给子组件传递一个style, 会绑定在子组件的容器元素上。如果一个子组件的根元素已经有了 style attribute,它会和从父组件上继承的值合并。

// 父组件
<HelloWorld style="fontSize: 16px" msg="Welcome to Your Vue.js App"/>

// 子组件
<template>
  <div class="test-wrapper" style="color: blue">
    注入信息: {{location}}
    <button @click="updateLocation" v-preReClick>点我点我</button>
  </div>
</template>

最终渲染效果如下:

image.png

v-on 监听器继承

click 监听器会被添加到 子组件的根元素,即那个原生的 <button> 元素之上。当原生的 <button> 被点击,会触发父组件的 onClick 方法。同样的,如果原生 button 元素自身也通过 v-on 绑定了一个事件监听器,则这个监听器和从父组件继承的监听器都会被触发。

// 父组件
<HelloWorld style="fontSize: 16px" msg="Welcome to Your Vue.js App" @click="parentClick"/>

// 子组件
<template>
  <div class="test-wrapper" style="color: blue">
    注入信息
    <button @click="confrim">点我点我</button>
  </div>
</template>
<script setup>
const confrim = () => {
  console.log('触发了子组件的点击事件');
}
</script>

渲染效果如下:

image.png

深层组件的继承

有些情况下一个组件会在根节点上渲染另一个组件。此时这个组件接收的透传 attribute 会直接继续传给另一个组件。

禁用Attributes的继承

如果你不想要一个组件自动地继承 attribute,你可以在组件选项中设置 inheritAttrs: false

<script> 
// 使用普通的 <script> 来声明选项 
export default { 
    inheritAttrs: false
} 
</script>

如果在script标签中使用了setup,则需要这样写:

<script>
export default {
  name: 'App',
  inheritAttrs: false
}
</script>
<script setup>
import HelloWorld from './components/HelloWorld.vue'

const parentClick = () => {
  console.log('触发了父组件的点击事件');
}

在子组件中如果需要获取这个属性就是v-bind="$attrs"来获取对应的内容。

多根节点的 Attributes 继承

和单根节点组件有所不同,有着多个根节点的组件没有自动 attribute 透传行为。如果 $attrs 没有被显式绑定,将会抛出一个运行时警告。因此需要将$attrs显示绑定

<template>
  <div class="test-wrapper" style="color: blue">
    注入信息
    <button @click="confrim" v-bind="$attrs.onClick">点我点我</button>
    <header>...</header>
    <main v-bind="$attrs">...</main>
    <footer>...</footer>
  </div>
</template>

在 JavaScript 中访问透传 Attributes

在 <script setup> 中使用 useAttrs() API 来访问一个组件的所有透传 attribute:

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

const attrs = useAttrs();
const confrim = () => {
  console.log('触发了子组件的点击事件');
}
</script>