属性和事件透传
属性和事件的透传需要借助一个内置 api $attrs
。
<my-input a="1" b="2" @change="() => {}" />
<template>
<div class="input-wrapper">
输入框:<el-input v-bind="$attrs"></el-input>
</div>
</template>
<script lang="ts">
export default {
mounted() {
console.log("attrs", this.$attrs)
}
}
</script>
但是这样直接使用 $attrs
透传的优先级会比组件自身的属性和事件优先级低。比如:
<template>
<div class="input-wrapper">
输入框:<el-input v-bind="$attrs"></el-input>
</div>
</template>
<script lang="ts">
export default {
props: ['a'],
emits: ['change'],
mounted() {
console.log("attrs", this.$attrs)
}
}
</script>
插槽透传
一般我们需要透传插槽的话,需要:
<my-input v-model="text" >
<template #prepend>
prepend
</template>
<template #append>
append
</template>
<template #suffix>
suffix
</template>
<template #prefix>
prefix
</template>
</my-input>
<template>
<div class="input-wrapper">
输入框:
<el-input v-bind="$attrs">
<template #prepend>
<slot name="prepend"></slot>
</template>
<template #append>
<slot name="append"></slot>
</template>
<template #suffix>
<slot name="suffix"></slot>
</template>
<template #prefix>
<slot name="prefix"></slot>
</template>
</el-input>
</div>
</template>
这样写有一些问题,一是繁琐,二是可能传递的插槽个数不同,导致不同的渲染逻辑(业务要求)。所以我们需要使用 $slots
这个 api。
插槽的本质是一个函数。
<my-input v-model="text" >
<template #prepend>
prepend
</template>
<template #append>
append
</template>
</my-input>
<template>
<div class="input-wrapper">
输入框:
<el-input v-bind="$attrs">
<template v-for="(_, name) in $slots" #[name]="scopedData">
<slot :name="name" v-bind="scopedData"/>
</template>
</el-input>
</div>
</template>
<script lang="ts">
export default {
mounted() {
console.log("slots", this.$slots)
}
}
</script>
ref 透传
在 vue 中 ref 是无法透传的,在 react 中可以通过 forwardRef 获取子组件。
所以我们只能将子组件内部的原组件库 ref 挂载到外部 二次封装的组件 ref 上。
<template>
<div class="input-wrapper">
输入框:
<el-input ref="elInput" v-bind="$attrs">
<template v-for="(_, name) in $slots" #[name]="scopedData">
<slot :name="name" v-bind="scopedData"/>
</template>
</el-input>
</div>
</template>
<script>
export default {
mounted() {
console.log("elInput", this.$refs.elInput)
for (const elInputKey in this.$refs.elInput) {
this[elInputKey] = this.$refs.elInput[elInputKey];
}
}
}
</script>