Vue3 透传 Attributes

Vue3 透传 Attributes

  • [1. Attributes 继承](#1. Attributes 继承)
    • [1.1 单个根文件继承(直接继承 attribute 和 事件监听器)](#1.1 单个根文件继承(直接继承 attribute 和 事件监听器))
    • [1.2 深层组件继承(一代单传,代代相传)](#1.2 深层组件继承(一代单传,代代相传))
  • [2. 禁用根节点 Attributes 继承](#2. 禁用根节点 Attributes 继承)
    • [2.1 使用方式(defineOptions( inheritAttrs: false}))](#2.1 使用方式(defineOptions( inheritAttrs: false})))
    • [2.2 指定非根节点继承 Attributes(结合 v-bind="attrs)](#2.2 指定非根节点继承 Attributes(结合 v-bind="attrs))
  • [3. 多根节点的 Attribute 继承(使用 v-bind="attrs" 指定一个继承)](#3. 多根节点的 Attribute 继承(使用 v-bind="attrs" 指定一个继承))
  • [4. 在 JavaScript 中访问透传 Attributes(const attrs = useAttrs())](#4. 在 JavaScript 中访问透传 Attributes(const attrs = useAttrs()))

1. Attributes 继承

透传 attribute,指的是传递给子组件 attribute 或者 v-on 事件监听器(但是子组件却没有声明 props 或 emits)。最常见的例子就是 class、style 和 id。

1.1 单个根文件继承(直接继承 attribute 和 事件监听器)

子组件 Mybutton.vue:

javascript 复制代码
<template>
  <button class="btn" @click="handleClick">Click Me</button>
</template>

<script setup>
function handleClick() {
  console.log('Button clicked!')
  // 这里可以添加更多的逻辑处理,例如调用其他方法或触发事件等。
  // 例如:emit('click', 'some data') 如果需要在父组件中接收点击事件的参数
}
</script>

<style lang="scss" scoped>

</style>

父组件 App.vue:

javascript 复制代码
<template>
  <MyButton @click="show" class="large" />
</template>

<script setup>
import MyButton from '@/components/Mybutton.vue';
function show() {
  console.log('clicked');
}
</script>

<style lang="scss" scoped>
.large{
  padding: 5px 10px;
}
</style>


可以看到,当子组件只有一个根节点,并没有向外传递任何 prop 或者 v-on 事件监听器时 ,却仍能够接收来自父组件的 class(子组件也有的话,就会进行合并) 和 事件(子组件也有的话,都会发生,但是先执行子组件的事件)。

总结:
(1)外部添加的 class 等 attribute 会和子组件根节点进行合并;
(2)外部定义的事件和子组件根节点定义的事件都会发生,但是内部更先执行。

1.2 深层组件继承(一代单传,代代相传)

将 1.1 单个根文件继承 中的代码进行改造。

创建一个 BaseButton.vue,使用原来子组件的代码:

javascript 复制代码
<template>
  <button class="btn" @click="handleClick">Click Me</button>
</template>

<script setup>
function handleClick() {
  console.log('Button clicked!')
  // 这里可以添加更多的逻辑处理,例如调用其他方法或触发事件等。
  // 例如:emit('click', 'some data') 如果需要在父组件中接收点击事件的参数
}
</script>

<style lang="scss" scoped>

</style>

MyButton.vue 在根节点渲染 BaseButton 组件:

javascript 复制代码
<template>
  <BaseButton />
</template>

<script setup>
import BaseButton from './BaseButton.vue';

</script>

<style lang="scss" scoped>

</style>

在 App.vue 中再使用 MyButton 组件:

javascript 复制代码
<template>
  <MyButton @click="show" class="large" />
</template>

<script setup>
import MyButton from '@/components/Mybutton.vue';
function show() {
  console.log('clicked');
}
</script>

<style lang="scss" scoped>
.large{
  padding: 5px 10px;
}
</style>


发现 <MyButton> 组件透传的 attribute 和 v-on 事件监听器 会继续传给 <BaseButton>

2. 禁用根节点 Attributes 继承

2.1 使用方式(defineOptions( inheritAttrs: false}))

如果你不想要一个组件自动地继承 attribute,可以直接在 <script setup> 中使用 defineOptions:

javascript 复制代码
<script setup>
defineOptions({
  inheritAttrs: false
})
// ...setup 逻辑
</script>

将 1.1 中的 子组件 MyButton.vue 进行改造:

javascript 复制代码
<template>
  <button class="btn" @click="handleClick">Click Me</button>
</template>

<script setup>
defineOptions({
  inheritAttrs: false
})
function handleClick() {
  console.log('Button clicked!')
}
</script>

<style lang="scss" scoped>

</style>

父组件 App.vue 不变:

javascript 复制代码
<template>
  <MyButton @click="show" class="large" />
</template>

<script setup>
import MyButton from '@/components/Mybutton.vue';
function show() {
  console.log('clicked');
}
</script>

<style lang="scss" scoped>
.large{
  padding: 5px 10px;
}
</style>


发现父组件的 attributes 和 v-on 事件监听器 都无法透传到子组件中了。

2.2 指定非根节点继承 Attributes(结合 v-bind="$attrs)

我们可以通过设定 inheritAttrs: false 和使用 v-bind="$attrs" 来实现非根节点的继承。

子组件 MyButton.vue:

javascript 复制代码
<template>
  <!-- 在组件外包一层 -->
  <div class="btn-wrapper">
    <button class="btn" v-bind="$attrs" @click="handleClick">Click Me</button>
  </div>
</template>

<script setup>
defineOptions({
  inheritAttrs: false
})
function handleClick() {
  console.log('Button clicked!')
}
</script>

<style lang="scss" scoped>
.btn-wrapper{
  display: inline-flex;
  padding: 20px;
  background-color: aqua;
}
</style>

根组件 App.vue:

javascript 复制代码
<template>
  <MyButton @click="show" class="large" />
</template>

<script setup>
import MyButton from '@/components/Mybutton.vue';
function show() {
  console.log('clicked');
}
</script>

<style lang="scss" scoped>
.large{
  padding: 5px 10px;
}
</style>


可以看到:

(1)父组件透传的 attributes 和 v-on 事件监听器都传递给了指定的非跟元素;

(2)值得注意的是,此时父组件的事件执行顺序优先于子组件。和之前有所不同。

3. 多根节点的 Attribute 继承(使用 v-bind="$attrs" 指定一个继承)

子组件 MyButton.vue:

javascript 复制代码
<template>
  <!-- 多个根节点的组件没有自动 attribute 透传行为 -->
  <button class="btn">Click Me 1</button>
  <button class="btn" v-bind="$attrs" @click="handleClick">Click Me 2</button>
  <button class="btn">Click Me 3</button>
</template>

<script setup>
function handleClick() {
  console.log('Button clicked!')
}
</script>

<style lang="scss" scoped>
.btn{
  margin-right: 10px;
}
</style>

父组件 App.vue:

javascript 复制代码
<template>
  <MyButton @click="show" class="large" />
</template>

<script setup>
import MyButton from '@/components/Mybutton.vue';
function show() {
  console.log('clicked');
}
</script>

<style lang="scss" scoped>
.large{
  padding: 5px 10px;
}
</style>


4. 在 JavaScript 中访问透传 Attributes(const attrs = useAttrs())

你可以在 <script setup> 中使用 useAttrs() API 来访问一个组件的所有透传 attribute。关键代码:

javascript 复制代码
<script setup>
import { useAttrs } from 'vue'

const attrs = useAttrs()
</script>

将 3 中的示例 子组件 MyButton.vue 进行改造,添加上述代码:

javascript 复制代码
<template>
  <!-- 多个根节点的组件没有自动 attribute 透传行为 -->
  <button class="btn">Click Me 1</button>
  <button class="btn" v-bind="$attrs" @click="handleClick">Click Me 2</button>
  <button class="btn">Click Me 3</button>
</template>

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

const attrs = useAttrs()
console.log('attrs:', attrs)

function handleClick() {
  console.log('Button clicked!')
}
</script>

<style lang="scss" scoped>
.btn{
  margin-right: 10px;
}
</style>

上一章 《Vue3 组件 v-model》

下一章 《Vue3 插槽》

相关推荐
whi2 小时前
一个小工具,解决了一个困扰 Vue 开发者多年的类型检查难题
vue.js·typescript
RuoyiOffice3 小时前
SpringBoot+Vue3+Onlyoffice 企业文件生命周期:上传、业务关联、权限、版本与安全清理
spring boot·vue3·文件管理·对象存储·权限控制·ruoyi office·附件管理
xcs1940514 小时前
前端 vue 的前端页面debugger 进不去
前端·javascript·vue.js
雪芽蓝域zzs17 小时前
第 5 节:Marker 点击弹出 InfoWindow 信息窗口
vue.js
大包子19 小时前
structuredClone vs lodash.cloneDeep:核心差异与选型指南
javascript·vue.js
雪芽蓝域zzs20 小时前
第 3 节:地图点击事件,点击获取经纬度
vue.js
WayneX20 小时前
开源 Vue 3 组件库 Morya UI:把组件、文档、AI 工具链一起做进一个包
前端·vue.js·前端框架
hai_android20 小时前
Chat 聊天模块功能总结
前端·javascript·vue.js
志尊宝1 天前
Vue3 零基础每日笔记(076):防抖节流的正确使用——搜索框、按钮防重复提交、滚动监听
javascript·vue.js·笔记
顽疲1 天前
从零用 Java 实现小红书 SpringBoot Vue UniApp(23)笔记话题多对多:一条笔记进多个话题池
java·vue.js·spring boot