el-tooltip组件append-to使用方法及源码解析

586 阅读2分钟

前言

最近在浏览 GitHub Element-plus Issues 时,我注意到 Issues #19905,问题描述为:“Tooltip 及其衍生组件在超出屏幕(挂载容器)时会导致容器尺寸变化”Element Plus Playground。在查看源码和 Vue 3 官方文档后,我找到了一个解决方案。

1. 原因分析

image.png

tooltip 组件使用了 transform: translate3d 定位。translate3d 改变了元素的实际位置,但这不会修改元素的布局模型(例如 position),它仍然会占据原来定义的空间。如果你通过 translate3d 将一个元素平移到视口外面,可能会导致页面超出视口的部分,从而出现滚动条。

为了避免这种情况,可以将元素插入到目标 DOM,而不是直接挂载到 body 标签。虽然官方文档提供了 append-to API 来实现这一点,但在实际使用时遇到了问题,append-to 并没有起到预期效果。出于好奇,查看了 Element-plus 的源码,以下是我的分析。

2. 源码分析

2.1 el-tooltip 组件

文件路径 packages\components\tooltip\src\tooltip.vue

image.png

从上图可以看到,tooltip 组件内还包含了一个子组件,接着继续往下查看源码。

2.2 el-tooltip-content 组件

文件路径 packages\components\tooltip\src\content.vue

image.png

这里依然有一层嵌套,继续查看。

2.3 el-teleport 组件

文件路径 packages\components\teleport\src\teleport.vue

image.png

<Teleport> 是 Vue3 的内置组件,它能够将组件的部分模板“传送”到 DOM 的其他位置,从而实现跨层级的元素插入

注意事项 image.png

3. 解决方案

从上述分析可以看出,append-to 无效的原因在于它需要等待 DOM 完全加载后才能挂载。为了修复这个问题,可以通过以下代码解决:

3.1 解决代码示例

<template>
  <el-tooltip
    :append-to="targetElement"
    trigger="click"
    content="Append to .target"
    placement="top"
  >
    <el-button class="target">Click to open tooltip</el-button>
  </el-tooltip>
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue'

const targetElement = ref<string>('')

onMounted(() => {
  targetElement.value = '.target'
})
</script>
<style scoped>
.target {
  position: relative;
}
</style>