🏅el-tooltip 组件在全屏状态下不显示提示框问题

📋大纲

🚀简介

1.问题解决

1.1.代码部分

1.2.核心部分

1.3.逻辑部分

2.核心思路

2.1.微/宏任务

3.个人理解


简介

自己遇到了这种问题也是找了许多文章,都进行了尝试,但是基本没什么作用;最后找到了这个一篇文章,看了一下,茅塞顿开;也顺利的解决了这个问题;后来那篇文章找不到了;自己写一篇吧,算是做个记录吧;

如果这篇文章解决了您的问题,帮忙点个赞哦👍;

✍创作不易;


🤖解决问题先~

👀代码部分
vue 复制代码
            <div class="rBtm" ref="tooltipBox">
                <div class="rBtmL">
                    <div class="personBox" v-for="(value, key, index) in dataLeft" :key="key">
                        <div class="personIcon">
                            <img :src="dataLeft[key].icon" alt="">
                        </div>
                        <div class="contentPerson" ref="contentPerson">
                            <el-tooltip :disabled="!isShowTooltip[index]" ref="myTooltip" :append-to-body="false" class="item" effect="dark"
                                :content="computedContent(formData[value.value])" placement="top">
                                <span ref="content" @mouseenter="toggleTooltip(index)" v-if="formData[value.value]" class="ellipsis">{{
                                    formData[value.value] }}</span>
                                <span v-else style="font-size: 14px;color: #ccc;">暂无数据</span>
                            </el-tooltip>
                        </div>
                        <div class="personKey">
                            {{ key }}
                        </div>
                    </div>
                </div>
                <div class="rBtmR">
                    <div class="rBtmR-item" v-for="(value, key) in dataRight" :key="key">
                        <span class="itemKey">{{ key }}</span>
                        <span class="itemValue" v-if="formData[value]">{{ formData[value] }}</span>
                        <span v-else style="font-size: 14px;color: #ccc;">暂无数据</span>
                    </div>
                </div>
            </div>

🎯核心部分

ref

1.tooltipBox 定位 父级盒子

2.myTooltip 定位 组件盒子

3.content 定位 自身

4.toggleTooltip 鼠标事件

5.第 10 行代码 鼠标悬停事件 引用@mouseenter="toggleTooltip(index)"

v-for

注意以上代码用的是 v-for


🎶逻辑部分
javaScript 复制代码
// path:src/utils/common.js

// 检查是否全屏
export function isFull () {
  // 判断浏览器是否处于全屏状态 (需要考虑兼容问题)
  // 火狐浏览器
  let screenFull = document.mozFullScreen ||
    document.fullScreen ||
    // 谷歌浏览器及Webkit内核浏览器
    document.webkitIsFullScreen ||
    document.webkitRequestFullScreen ||
    document.mozRequestFullScreen ||
    document.msFullscreenEnabled
  if (screenFull === undefined) {
    screenFull = false
  }
  return screenFull
}
...
javaScript 复制代码
import { isFull } from '@/utils/common.js';

export const bimGeoMixin = {
    data() {
        return {
            isShowTooltip: [],  // 控制每个 el-tooltip 的显示状态,使用数组来保存多个 tooltip 的状态
        };
    },
    methods: {
        toggleTooltip(index) {
                // 如果全屏状态下,需要特殊处理
                if (!isFull()) return;

                setTimeout(() => {
                    if (this.$refs.myTooltip) {
                        this.$refs.myTooltip.forEach((item) => {
                            // 可以打印 item 看看呢;console.log(item,'item',index)
                            this.$refs.tooltipBox.appendChild(item.popperVM.$el);
                        });
                    }
                }, 100);
        }
};

🤖核心思路

逻辑

🌼 首先要给鼠标悬停的文字部分加上一个鼠标悬停事件;

1.在此事件内判断当前是否为全屏状态 isFull

2.判断浏览器是否处于全屏状态 (需要考虑兼容问题)

3.如果不是全屏状态则不需要特殊处理,直接 return

4.因为某个盒子进入全屏之后,会发生重排重绘,虽然 Vue 的 DOM 更新可能已经完成,但全屏状态触发的布局变化可能还在进行中,因此 this.$nextTick(微任务) 的时机不够晚,无法捕捉到这些变化。所以这里我是用了setTimeout(宏任务)延迟执行了 100 毫秒,给浏览器足够的时间完成全屏引发的布局计算和渲染操作。

全屏模式下的重绘和重排有时比 Vue 的 DOM 更新要慢一些。setTimeout 会等到这些操作结束后再执行代码,从而确保 el-tooltip 的 DOM 正确渲染并可以被附加到新的位置。

5.因为数据是多个,所以代码中用到了 v-for ,所以这里的el-tooltip是多个的,所以需要 变量 isShowTooltip去保存每一个的状态,当然 在toggleTooltip事件中需要传递index,以便分辨出应该触发哪一个el-tooltip组件的提示框;


🤖个人理解

全屏状态下,el-tooltip无法展示提示框的原因可能是因为以下几点:

1.el-tooltip 这些元素都是插入到body里面的,而当某一div全屏后由于层级原因无法显示这些组件;

2.全屏模式下,浏览器会对 DOM 进行重新渲染和布局。在这种情况下,tooltip 可能无法正确计算其位置,导致其未能显示或显示在错误的位置。

上述代码主要是获取 el-toolitp 元素,在元素全屏时,找到el-tooltip的祖父元素然后重新插入到 祖父父级盒子里;


⏰微任务、宏任务

概念:

宏任务(Macrotask)微任务(Microtask) 是指在 JavaScript 异步任务处理中的两种不同类型的任务。这两种任务的执行顺序和优先级不同,理解它们有助于掌握 JavaScript 的事件循环机制

宏任务:

宏任务 是指由宿主环境(如浏览器或 Node.js)调度的任务,每个宏任务会在事件循环的每次循环中执行一个。 常见的宏任务

  • setTimeout

  • setInterval

  • setImmediate(Node.js 环境)

  • I/O 事件回调(如文件读取、网络请求等)

  • UI 渲染(浏览器的重排、重绘)

  • 用户输入事件(如 clickmousedownkeyup 等)

微任务:

微任务 的执行时机比宏任务更早,它们会在当前宏任务执行完毕后、下一个宏任务开始之前执行。微任务通常用于处理异步操作的后续逻辑,比如 Promise 的回调。

常见的微任务:

  • Promise.thenPromise.catchPromise.finally
  • MutationObserver
  • process.nextTick(Node.js 环境)
  • nextTick(()=>{}) (vue)
宏任务与微任务的区别:

执行顺序:

  • 在每轮事件循环中,宏任务会首先执行。
  • 在宏任务执行完后,所有微任务队列中的任务会依次执行,直到微任务队列清空后才开始执行下一轮宏任务。

优先级:

  • 微任务的优先级比宏任务高,因此微任务会在当前的宏任务完成后立即执行,而无需等待下一个事件循环。

任务调度:

  • 宏任务是由事件循环调度的。
  • 微任务是在每个宏任务执行完毕后立即执行的,不会等到下一轮事件循环。
事件循环中的宏任务和微任务流程:
  • 先执行同步代码,所有同步代码都属于当前宏任务
  • 当前宏任务执行完后,执行所有的微任务(如 Promise 回调)。
  • 如果微任务队列清空,检查是否有新的宏任务(如 setTimeout 回调),如果有,执行新的宏任务。
  • 重复上述过程,不断循环。

结束~ 拜拜;

相关推荐
m0_748257186 分钟前
Spring Boot FileUpLoad and Interceptor(文件上传和拦截器,Web入门知识)
前端·spring boot·后端
桃园码工23 分钟前
15_HTML5 表单属性 --[HTML5 API 学习之旅]
前端·html5·表单属性
百万蹄蹄向前冲1 小时前
2024不一样的VUE3期末考查
前端·javascript·程序员
轻口味1 小时前
【每日学点鸿蒙知识】AVCodec、SmartPerf工具、web组件加载、监听键盘的显示隐藏、Asset Store Kit
前端·华为·harmonyos
alikami1 小时前
【若依】用 post 请求传 json 格式的数据下载文件
前端·javascript·json
吃杠碰小鸡2 小时前
lodash常用函数
前端·javascript
emoji1111112 小时前
前端对页面数据进行缓存
开发语言·前端·javascript
泰伦闲鱼2 小时前
nestjs:GET REQUEST 缓存问题
服务器·前端·缓存·node.js·nestjs
m0_748250032 小时前
Web 第一次作业 初探html 使用VSCode工具开发
前端·html
一个处女座的程序猿O(∩_∩)O2 小时前
vue3 如何使用 mounted
前端·javascript·vue.js