想要写一个Popover,计算元素位置使用的是floating-ui
,需要获取触发元素的Ref和Popover内容的Ref来进行定位。
触发元素和内容通过插槽传入,遇到的问题是如何获取插槽内元素的Ref
Popover 伪代码:
<template>
<slot name="trigger" />
<teleport to="body">
<div v-if="show" class="absolute inset-0">
<slot />
</div>
</teleport>
</template>
使用:
<Popover>
<template #trigger>
<button >test</button>
</template>
<div>
Popover
</div>
</Popover>
目前我能想到的办法就是在触发元素和内容外套一层div,然后用div的Ref
<script setup>
const triggerRef = ref()
const floatingRef = ref()
</script>
<template>
<div ref="triggerRef">
<slot name="trigger" />
</div>
<teleport to="body">
<div ref="floatingRef" v-if="show" class="absolute inset-0">
<slot />
</div>
</teleport>
</template>
但是这样就多了一层节点,在想能不能有更好的解决方案?
看了别的组件库,目前已经找到一种解决方案:
就是直接通过
useSlots()
获取插槽的 vNode,然后手动渲染,并绑定ref。代码如下:
但是这样有个缺点,WebStorm 写插槽的时候不会有提示,甚至有警告更新
以上问题可以通过 Vue3.3 新增宏
defineSlots()
来解决,defineSlots()
用于定义插槽。具体使用 查看Vue文档