在 Vue3 中,透传是一种在父子组件中,仅通过组件属性传递参数的方式,不需要单独使用 props
或 emit
对传递的参数进行显式声明。
透传规则
默认情况下,透传会将参数传递到子组件中,仅对于对 class
和 style
的值进行合并。如果子组件中仅嵌套了另一个子组件,那么透传会继续向下传递。
html
<!-- Child.vue -->
<template>
<sub-child></sub-child>
</template>
但是,如果子组件是一个多层的布局,那就需要手动为每个参数指定透传的目标。否则,vue 将会发出像下面这样的警告。
Child.vue?t=1753428210893:53 [Vue warn]: Extraneous non-props attributes (text) were passed to component but could not be automatically inherited because component renders fragment or text or teleport root nodes.
这时,我们就需要使用 $attrs
手动为其指定传递的布局。
html
<!-- Child.vue -->
<template>
<div>{{ $attrs.text }}</div>
<button></button>
</template>
如果不希望某个子组件自动继承透传,那么可以在子组件中设置 inheritAttrs: false
取消透传自动继承。
javascript
<script setup>
defineOptions({
inheritAttrs: false
})
</script>
透传与组件父子通信
透传除了能够传递参数,还能够为子组件传递函数。通过使用 v-bind
将父组件的任意函数透传到子组件中,配合 callback 函数的入参,我们就能将子组件的参数回传给父组件,并通过父组件的函数进行数据更新。
html
<!-- Parent.vue -->
<template>
<div>
<p>父组件变量值:{{ count }}</p>
<br />
<child :callback="changeCount" :text="text"></child>
</div>
</template>
<script setup>
import { ref } from "vue";
import Child from "./Child.vue";
const count = ref(0);
const text = ref("这是被透传的值");
function changeCount(newCount) {
count.value = newCount;
}
</script>
html
<!-- Child.vue -->
<template>
<div>{{ $attrs.text }}</div>
<button @click="$attrs.callback(num)">修改父组件变量</button>
</template>
<script setup>
const num = ref(10);
</script>
预览效果如下
此外,我们还可以在 <script setup>
中使用 useAttrs()
API 来访问一个组件的所有透传。例如直接调用
html
<!-- Child.vue -->
<script setup>
import { ref } from "vue";
import { useAttrs } from "vue";
const num = ref(10);
const attrs = useAttrs();
attrs.callback(num.value);
</script>
结语
相比与 Props
,这种传递更加符合直觉,但是也因为不需要声明的特点,在复杂布局中难以将参数建立关联,必须回到父组件中理解传递的参数。所以,只建议在清晰的布局结构中使用这种技术,防止带来技术上的心智负担。