Vue 中怎样获取具名 slot 的 DOM 节点

需求

我是想实现一个 popover 组件,类似 Element UI 的 popover,使用的时候用 popover 组件包裹目标元素,在目标元素周围展示弹出内容。其中一个重点是想获取到目标元素相对屏幕的位置和宽高信息。

我看了下 Element UIpopover 组件也是这样实现的,和我的区别在于声明 slot 时使用的是旧版语法,也就是直接在元素上声明 slot(具体代码见下面),我试了下这种语法确实是能通过 this.$slots?.xxx?.[0].elm 获取到 slot 元素的,但是目前 Vue 官方已经废弃了这种语法,新版语法读取到的 elmundefined

大致代码如下:

<!-- popover 组件 -->
<template>
  <span>
    <div :style="position" class="common-popover-container" ref="popper">
    </div>
    <slot name="reference"></slot>
  </span>
</template>

<!-- 组件使用 -->
<popover>
    <!-- 新版语法 -->
    <template v-slot:reference>
        <button>在我周围显示弹出框</button>
    </template>
    <!-- Element 使用的旧语法 -->
    <button slot="reference">在我周围显示弹出框</button>
</popover>

----------更新分割线-----------

问题

我可能没有表达清楚,我的结构是这样,声明一个组件 AA 组件接受一个具名 slot,然后在 B 组件中使用 A,需求是想在 A 中获取到 B 使用时给 A 传递的 slot 的相关信息。

这种跨组件的我了解到的好像没办法直接通过 ref 拿到对应元素,用官方推荐的 <template v-slot:xxx> 方式包裹的 slot 就无法读取 $slots 拿到对应的 elm,但是官方废弃的 <span slot="xxx"> 语法包裹的 slot 可以通过读取 $slots 获取到 elm。

所以就想知道有没有什么官方推荐的解决办法。

大致代码如下:示例 demo

const A = {
  mounted() {
    this.$nextTick(() => {
        console.log(this.$slots?.other?.[0].elm) // undefined
    })
  },
  template: `
    <div>
       <slot name="other"></slot>
    </div>
  `
}

const B = {
  components: {
    A
  },
  template:  `
    <A>
      <template v-slot:other>
        <span ref="test">我是具名 slot</span>   
      </template>
    </A>
  `
}

----------原问题------------
如题,怎样能获得 Vue 组件中具名 slot 的 DOM 节点。

我试了下目前 Vue 支持的几种 slot 声明方式,发现之前的 <span slot="xxx">我是插槽</span> 的方式是可以拿到该插槽渲染的真实节点的,但是该语法已经被废弃,所以想问下在新的语法里面怎样能获得 Vue 组件中具名 slot 的 DOM 节点。具体情况见下面示例代码

我主要是通过这样获取到这个节点的位置和宽高信息。

示例代码
<template v-slot:xxx>
    <span>我是插槽</span>
</template>
<!-- this.$slots.xxx?.[0]?.elm 是 undefined -->

<span slot="xxx">我是插槽</span>
<!-- this.$slots.xxx?.[0]?.elm 是该节点 -->

<span>我是默认插槽</span>
<!-- 不通过 template 包裹的默认插槽 -->
<!-- s.$slots.default?.[0]?.el 是该节点 -->
阅读 12.5k
1 个回答

建议 popover 组件这样写:

<!-- popover 组件 -->
<template>
  <span>
    <div :style="position" class="common-popover-container" ref="popper">
    </div>
    <div ref="reference">
      <slot name="reference"></slot>
    </div>
  </span>
</template>

就可以通过 this.$refs.reference 拿到 slot 里面内容的 dom 了。
$scopeSlots 只能拿到 vnode,确实无法获取 dom。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题