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 事件监听器(但是子组件却没有声明 propsemits)。最常见的例子就是 classstyleid

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> 组件透传的 attributev-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>


发现父组件的 attributesv-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 插槽

相关推荐
慧一居士6 小时前
在Vue项目中平滑地引入HTML文件
前端·vue.js
小白学过的代码7 小时前
videojs增加视频源选择框小工具
javascript·vue.js·音视频
clausliang7 小时前
实现一个可插入变量的文本框
前端·vue.js
Aress"8 小时前
uniapp设置vuex公共值状态管理
javascript·vue.js·uni-app
一 乐10 小时前
口腔健康系统|口腔医疗|基于java和小程序的口腔健康系统小程序设计与实现(源码+数据库+文档)
java·数据库·vue.js·小程序·毕设
旺财是只喵10 小时前
vue项目里使用3D模型
前端·vue.js
Java陈序员10 小时前
完全开源!一款基于 SpringBoot + Vue 构建的社区平台!
vue.js·spring boot·github·社区
小纯洁w10 小时前
vue3.0 使用el-tree节点添加自定义图标造成加载缓慢的多种解决办法
前端·javascript·vue.js
叫我詹躲躲10 小时前
Vue 3 ref 与 reactive 选哪个?
前端·vue.js