Vue3: 透传的说明 + Props和 Attrs的区别

题外话:Vue 接触的很早从最早的vue1开始,那时候也拿来做了些apps,但是也是很早就放弃了然后一直深耕在React上.当时的种种考虑中有一点就是vue太不稳定了(版本上)其实也很明智.但是这些都不妨碍Vue是最流行和高效的前端框架之一的地位.现在招聘和项目vue占的比重一直都是很大的. 前阵子Vue3出来了.准备学习下Vue3. 期望这次的版本能稳定一段时间吧.至少别整个vue4,5然后大变样.

 1.什么是透传

 其实当我看到这次个词的第一印象就是props的值传递.但是这其实太小看vue了.

“透传 attribute”指的是传递给一个组件,却没有被该组件声明为 props 或 emits 的 attribute 或者 v-on 事件监听器。最常见的例子就是 classstyle 和 id

官方的解释其实很通透.只不过是在我理解完透传以后再回头看这句话. 不看代码单纯从这个词来理解就很好理解,直接让值穿透到子组件上.而且Vue比较牛的是.这个透传是自动设置到组件的元素上(如果没有指定,下面会说到). 

2. 自动透传
 


<script setup lang="ts">
// 引入子组件
import Com from './com1.vue'

interface Props {
  msg?: string;
}
defineProps<Props>();

// 需要透传的函数
 function handleOnClick () {
    console.log("success")
}

</script>
<template>
    {{ msg }}

/*
* 这里透传了2个属性值
* handleOnClick: 一个v-on的函数
* message: 这个是props,不是透传 注意不要弄混
* class: 这个是我们需要透传的class
**/

    <Com @click="handleOnClick" message="Evan" class="fontRed"> click me </Com>
</template>
<style >
/**
* 透传的class
*/
    .fontRed {
        color: red;
    }
</style>

 子组件: com1.vue

<script setup lang="ts">
    interface Prop {
        message?: string;
    }
    defineProps<Prop>()
</script>

<template >
  <div>{{message}} -- 这个值是props 传递的值,但是颜色是透传过来的</div>
</template>

运行后结果
 可以看到点击后的控制台输入了透传过来的函数.这个自动透传真的有点意思.

当然实际项目中很少有一个组件就一个dom节点的存在,那透传怎么能对应到自己想要的节点上呢.

3.指定透传

使用 

    defineOptions({
        inheritAttrs: false,
    })

并且配合 $attrs

修改下子组件如下

 

<script setup lang="ts">
    interface Prop {
        message?: string;
    }
     defineProps<Prop>()
    defineOptions({
        inheritAttrs: false,
    })

</script>

<template >
// 指定div的click event 获取透传的函数
<div @click="$attrs.onClick" >{{message}} -- 这个值是props 传递的值,但是颜色是透传过来的</div>
// 指定button元素的class获取透传的class
<button :class="$attrs.class">
    <slot></slot>
</button>
</template>

效果如下

4.爷孙组件透传

其实官网的介绍也就到这里了.但是在实际项目中我们的组件深度往往不仅限于这2层,再加一个孙子组件透传怎么传呢?
其实很简单v-bind:$attrs 透传绑定到孙子组件

首先来个简单的孙子组件

<script setup lang="ts">
    interface Prop {
        test?: string;
    }
    defineProps<Prop>()
</script>

<template >

<div >{{test}} -- 透传过来变成红色字体了</div>
</template>

修改儿子组件

<script setup lang="ts">
// 引入孙子组件
import ComA from './com2.vue'
    interface Prop {
        message?: string;
    }
     defineProps<Prop>()
    defineOptions({
        inheritAttrs: false,
    })

</script>

<template >

<div  >{{message}} </div>
<button>
    <slot></slot>
</button>
// 透传属性到孙子节点
<ComA v-bind="$attrs"/>
</template>

运行下看效果

可以看到透传成功到了孙子组件 

官方还提供了一个useAttrs 函数可以在js代码中访问一个组件所有透传的属性
 

import {useAttrs} from 'vue'

const attrs = useAttrs()

console.log(attrs)

5. attrs的特点


说了半天透传 总结下透传的特别
attrs:
定义上:attrs($attrs)是一个对象,包含传递给组件的所有未明确声明为道具的属性和监听器。
使用方法 对于属性转发非常有用,尤其是在创建高阶组件或包装组件时,你需要将属性传递给子元素或组件。
自动继承: 未定义为透传的属性会自动添加到组件的根元素中。
没有验证:attrs 不提供验证或默认值。
静态性:attrs 不是响应性的,不能像props一样跟踪它的变化。

6. props的不同

声明: props: 必须在子组件中明确声明。
            Attrs: 自动包含传递给组件的所有非props属性。

使用方法    Props: 用于传递特定数据和处理程序。
                  Attrs: 用于传递任意属性和监听器。

验证和默认值:props: 可以有类型、默认值和验证器。
                        Attrs: 不提供验证或默认值。

响应性 props: 具有反应性,在父节点更新时更新。
           attrs: 本质上不是反应式的,但可在反应式上下文中使用。

总结下:


Attrs给我的感觉更像是一个对props, emit的补充. 不像React在类似透传中使用{...props} 这样随便丢过去或者直接uesReducer, useContext这么复杂,vue的透传是很有目的性的.传递+赋值书写起来很流畅,需要注意的是:如果父组件传递了一个方法,但是子组件忘记使用或者指定分配而被透传自动分配.这样还是比较麻烦的

<think>嗯,用户问的是Vue2的$attrsVue3的$attrs的用法区别。我需要先回忆一下这两个版本中attrs的行为有什么不同。 首先,Vue2中的$attrs包含了父作用域中不作为prop被识别(且获取)的特性绑定(classstyle除外)。也就是说,如果子组件没有在props里声明某个属性,这个属性就会出现在$attrs里。在Vue2中,当子组件使用v-bind="$attrs"时,这些属性会应用到子组件的根元素上。但是,如果子组件的根元素已经有了相同的属性,父组件过来的值会覆盖子组件本身的属性。不过,在Vue2里,如果子组件里嵌套了另一个组件,就需要手动通过v-bind="$attrs"递下去,否则属性不会自动递到更深层的子组件。 然后是Vue3的变化。Vue3中的$attrs现在包含了所有递给组件的属性,包括classstyle。这点Vue2不同,Vue2是排除这两个的。另外,Vue3在继承父组件递的属性时,如果子组件的根元素已经有相同的属性,父组件的属性会子组件的合并,而不是覆盖。比如,父组件了一个class="parent-class",子组件根元素有class="child-class",结果会是两者的合并。这在Vue2里是不会发生的,Vue2里父组件的会覆盖子组件的。 还有,Vue3中的v-bind="$attrs"现在会将所有属性(包括事件监听器)递到子组件,而Vue2中事件监听器是在$listeners里的,需要单独处理。Vue3把$listeners移除了,合并到了$attrs里,这样在递时更方便,不需要同时绑定$attrs$listeners。 另外,在Vue3中,如果组件有多个根节点(Fragment特性),需要显式绑定$attrs,否则会有警告。而Vue2中组件只能有一个根节点,所以自动应用到根元素上没问题,但Vue3允许多个根节点,这时候就需要开发者自己决定在哪里绑定$attrs。 举个例子,比如在Vue2中,子组件接收父组件的placeholder属性,但如果没有声明为prop,就会在$attrs里,然后通过v-bind="$attrs"递给input元素。而在Vue3中,同样的情况,但class也会被包含,并且如果子组件有多个根节点,必须手动绑定,否则不会自动应用。 可能用户在使用Vue2升级到Vue3时遇到了问题,比如样式不合并或者事件监听器失效,这时候需要了解$attrs的变化。用户可能需要知道如何正确递属性处理多个根节点的情况,以及为什么在Vue3中classstyle会被包含在$attrs里。 总结一下,Vue3的$attrs更全面,包含所有属性,合并行为改变,事件监听器合并到attrs,以及多根组件需要显式绑定。这些区别需要详细说明,帮助用户避免迁移中的常见问题。</think>好的!我将从**用法对比****核心区别**两个方面,帮你梳理 Vue2 Vue3 中 `$attrs` 的异同。 --- ### 一、基础概念 `$attrs` 是 Vue 用于接收**父组件递的非 prop 属性**的容器(例如 `class`、`style`、原生事件等)。它在组件层级嵌套时,常用于属性。 --- ### 二、Vue2 中的 `$attrs` #### 1. 特性 - **排除已声明的 props**:父组件递的属性若未被 `props` 接收,则进入 `$attrs` - **不包含 `class` `style`**:这两者会被单独提取到组件根元素上 - **需要手动**:若要将属性递给更深层子组件,需显式使用 `v-bind="$attrs"` #### 2. 代码示例 ```html <!-- 父组件 --> <ChildComponent id="parent-id" class="parent-class" data-test="123" /> <!-- 子组件 (ChildComponent.vue) --> <template> <div> <GrandChild v-bind="$attrs" /> </div> </template> <script> export default { // 未声明 props: [&#39;dataTest&#39;] } </script> ``` - `$attrs` 内容:`{ id: "parent-id", data-test: "123" }` - `class="parent-class"` 自动附加到子组件根元素 `<div>` --- ### 三、Vue3 中的 `$attrs` #### 1. 核心变化 - **包含 `class` `style`**:不再自动附加到根元素,而是进入 `$attrs` - **合并代替覆盖**:若子组件根元素已有同名属性,Vue3 会**合并值**而非覆盖 - **移除 `$listeners`**:事件监听器合并到 `$attrs` 中(如 `@click`) - **多根节点需显式绑定**:若组件有多个根元素,需手动指定 `$attrs` 位置 #### 2. 代码示例 ```html <!-- 父组件 --> <ChildComponent id="parent-id" class="parent-class" @click="handleClick" /> <!-- 子组件 (ChildComponent.vue) --> <template> <div :class="$attrs.class"> <GrandChild v-bind="$attrs" /> </div> </template> <script> export default { // 需要手动处理 class } </script> ``` - `$attrs` 内容:`{ id: "parent-id", class: "parent-class", onClick: handleClick }` --- ### 四、关键区别总结 | **特性** | **Vue2** | **Vue3** | |-------------------------|-----------------------------------|-----------------------------------| | `class` & `style` | 不包含在 `$attrs`,自动附加根元素 | 包含在 `$attrs`,需手动处理 | | 同名属性处理 | 父级覆盖子级 | 合并父级子级的值 | | 事件监听器 | 存放在 `$listeners` | 合并到 `$attrs` 中 | | 多根组件 | 不支持多根组件 | 必须显式指定 `v-bind="$attrs"` | --- ### 五、使用建议 1. **Vue2 迁移到 Vue3**: - 检查 `class` `style` 是否被正确处理 - 替换 `$listeners` 为 `$attrs` 2. **第三方组件**: ```html <!-- Vue3所有属性事件 --> <template> <ThirdPartyComponent v-bind="$attrs" /> </template> ``` 3. **合并根元素属性**: ```html <!-- 合并父级自身的 class --> <div :class="[localClass, $attrs.class]"></div> ``` --- 理解这些差异能帮助你更精准地控制组件间的属性递!如果有具体场景问题,可以进一步探讨。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值