当前位置: 首页 > 知识库问答 >
问题:

javascript - 如何在Vue中获取插槽内元素的Ref?

柴文林
2024-02-18

想要写一个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>

但是这样就多了一层节点,在想能不能有更好的解决方案?

共有2个答案

山煜祺
2024-02-18

看了别的组件库,目前已经找到一种解决方案:

就是直接通过 useSlots() 获取插槽的 vNode,然后手动渲染,并绑定ref。

代码如下:

<script setup>import {ref, useSlots} from 'vue'const triggerRef = ref()const floatingRef = ref()const slots = useSlots()const triggerArr = slots?.trigger?.()// 获取vNode(真实场景,这一步需要校验插槽传过来的值。如果值是字符串或多个元素等情况,需要进一步处理)const TriggerVNode = triggerArr[0]</script><template>  <TriggerVNode ref="triggerRef" />  <teleport to="body">    <div ref="floatingRef" v-if="show" class="absolute inset-0">      <slot />    </div>  </teleport></template>

但是这样有个缺点,WebStorm 写插槽的时候不会有提示,甚至有警告

更新

以上问题可以通过 Vue3.3 新增宏 defineSlots() 来解决,defineSlots() 用于定义插槽。
具体使用 查看Vue文档

宗政唯
2024-02-18

在Vue中,你可以使用ref()函数来获取插槽内元素的引用。ref()函数返回一个响应式引用,可以用来访问DOM元素或组件实例。

在你的例子中,你可以在Popover组件的setup()函数中创建一个ref,并将其绑定到插槽元素上。然后,你可以在模板中使用ref来获取插槽内元素的引用。

以下是一个示例代码:

<template>  <slot name="trigger" ref="triggerRef" />  <teleport to="body">    <div v-if="show" class="absolute inset-0">      <slot ref="popoverContent" />    </div>  </teleport></template><script setup>import { ref } from 'vue';const triggerRef = ref(null);const popoverContent = ref(null);</script>

在上面的代码中,我们在setup()函数中创建了两个reftriggerRefpopoverContent。然后,我们将这两个ref分别绑定到插槽元素上,通过在插槽标签上添加ref属性并指定对应的引用名称。

现在,你可以通过triggerRef.valuepopoverContent.value来访问插槽内元素的引用。注意,在使用引用时需要添加.value来获取实际的值。

使用这种方法,你就不需要在触发元素和内容外套一层div来获取引用了。

 类似资料:
  • 问题内容: 我想替换html元素中的内容,所以为此使用了以下功能: 上面的方法效果很好,但是问题是我要替换其内容的页面上有多个html元素。因此,我不能使用id而是使用类。有人告诉我javascript不支持任何类型的内置get element by class函数。那么如何修改以上代码以使其与类(而不是ID)一起使用? PS我不想为此使用jQuery。 问题答案: 此代码应在所有浏览器中都有效。

  • vue3中,怎么获取子组件插槽内的DOM实例或者说ref? 我尝试这样获取,但是获取不到:

  • 问题内容: 我一定在想这个错误。 我想在我使用Webdriver / Selenium 2访问的页面上获取元素的内容(在本例中为formfield) 这是我的损坏代码: 结果如下: (请注意空白行)我知道该元素包含内容,因为我只是使用.sendkeys使用先前的命令将它们填充在其中,并且在脚本运行时可以在实际的网页上看到它们。 但我需要将内容重新放入数据中。 我该怎么读?最好以通用方式,以便我可以

  • 问题内容: 我正在寻找一种从样式标签中设置了样式的元素中检索样式的方法。 在身体里 我正在寻找不使用库的直接javascript。 我尝试了以下操作,但始终收到空白: 我注意到,如果我已使用javascript设置了样式,但无法使用样式标签,则只能使用以上内容。 问题答案: 该属性仅让您知道在该元素中定义为内联的CSS属性(以编程方式或在元素的style属性中定义),应该获取计算出的style。

  • 我希望能够获取<template #loadMore>中 id为"is_load"的div元素 但是ref无法引用到 ,在onMounted函数中使用nextTick回调打印处理这个dom也是空的,等待渲染后也不行 有什么方法可以操作到dom vue 无法获取到template中的dom元素?

  • 在调用这个组件的地方 接收childer组件作为插槽,在parent中 获取不到默认插槽的属性b,不知道为什么