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 插槽

相关推荐
让我上个超影吧19 小时前
基于SpringBoot和Vue实现CAS单点登录
前端·vue.js·spring boot
gg1593572846020 小时前
JavaScript 核心基础
前端·javascript·vue.js
北辰alk21 小时前
从零设计一个Vue路由系统:揭秘SPA导航的核心原理
前端·vue.js
计算机毕设VX:Fegn089521 小时前
计算机毕业设计|基于springboot + vue个人博客系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·课程设计
幽络源小助理1 天前
SpringBoot+Vue美食网站系统源码 | Java餐饮项目免费下载 – 幽络源
java·vue.js·spring boot
这是个栗子1 天前
【Vue代码分析】vue方法的调用与命名问题
前端·javascript·vue.js·this
全栈前端老曹1 天前
【前端路由】Vue Router 动态导入与懒加载 - 使用 () => import(‘...‘) 实现按需加载组件
前端·javascript·vue.js·性能优化·spa·vue-router·懒加载
北辰alk1 天前
Vue 3 深度解析:watch 与 watchEffect 的终极对决
vue.js
LYFlied1 天前
Vue.js 中的 XSS 攻击防护机制详解
前端·vue.js·xss
冥界摄政王1 天前
Cesium学习第二章 camera 相机
node.js·html·vue3·js·cesium