题外话:Vue 接触的很早从最早的vue1开始,那时候也拿来做了些apps,但是也是很早就放弃了然后一直深耕在React上.当时的种种考虑中有一点就是vue太不稳定了(版本上)其实也很明智.但是这些都不妨碍Vue是最流行和高效的前端框架之一的地位.现在招聘和项目vue占的比重一直都是很大的. 前阵子Vue3出来了.准备学习下Vue3. 期望这次的版本能稳定一段时间吧.至少别整个vue4,5然后大变样.
1.什么是透传
其实当我看到这次个词的第一印象就是props的值传递.但是这其实太小看vue了.
“透传 attribute”指的是传递给一个组件,却没有被该组件声明为 props 或 emits 的 attribute 或者
v-on
事件监听器。最常见的例子就是class
、style
和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的透传是很有目的性的.传递+赋值书写起来很流畅,需要注意的是:如果父组件传递了一个方法,但是子组件忘记使用或者指定分配而被透传自动分配.这样还是比较麻烦的