🔥 我封装了一个会“思考”的指令!Element-Plus Tooltip 自动检测文本溢出,优雅展示

引言:会"思考"的指令!

你是否还在为页面上成堆的 el-tooltip 组件而头疼?只为了一行可能溢出、可能不溢出的文本,每个地方都要手动包裹一层,代码又臭又长,性能还不美观。今天,我带大家封装一个"会思考"的 Vue 自定义指令 v-ellipsis-tooltip 。它能让 ElTooltip 变得智能化:只在文本内容溢出时,才自动出现 Tooltip;如果文本完整显示,则什么都不发生。 完美实现"按需展示",让代码更简洁,体验更优雅!"

一、实现思路 & 核心技术点

  1. 指令的职责 :在元素 mounted 时,判断其内容是否溢出。
  2. 关键 API :使用 el.scrollHeight > el.clientHeight 检测溢出。
  3. 灵魂所在 :使用 Vue 3 的 createVNoderender 函数,动态创建并挂载 ElTooltip 组件。
  4. 优雅替换 :巧用 nextTick 等待渲染完成,并妥善处理原始元素的 classstyleVue 的 Scoped CSS 数据属性(data-v-* ,确保样式不丢失且响应式不受影响。

二、代码实现与逐行解析

javascript 复制代码
import { createVNode, render, nextTick } from 'vue'
import { ElTooltip } from 'element-plus'

export const vEllipsisTooltip = {
  async mounted(el, binding) {
    // 等待一个 Tick,确保元素已渲染完成
    await nextTick()

    // 1. 核心逻辑:检测文本是否溢出
    const isOverflowed = el.scrollHeight > el.clientHeight
    if (!isOverflowed) return // 无溢出,直接返回,不做任何操作

    // 2. 保存元素的原始内容、类名和样式,以备后用
    const originalContent = el.innerHTML
    const originalClass = el.className
    const originalStyle = el.style.cssText

    // 3. 创建 Tooltip 的虚拟节点 (VNode)
    const tagNameLower = el.tagName.toLowerCase() // 获取原元素的标签名(如 'div', 'p')
    const vnode = createVNode(
      ElTooltip, // 要渲染的组件
      { // 组件的 Props
        content: binding.value || el.textContent, // 支持指令传值(自定义提示内容),不传则用元素文本
        placement: 'top' // 提示框位置,可扩展为指令参数
      },
      { // 组件的 Slots
        default: () => 
          createVNode( // 创建原元素的 VNode 作为 Tooltip 的默认插槽内容
            tagNameLower,
            {
              innerHTML: originalContent, // 还原原始 HTML 结构
              class: originalClass, // 还原 Class
              style: originalStyle // 还原 Style
            }
          )
      }
    )

    // 4. 将 VNode 渲染到一个临时容器中
    const container = document.createElement('div')
    render(vnode, container)

    // 5. 【关键步骤】安全替换 DOM 节点
    const newEl = container.firstElementChild // 渲染出的真实 DOM 节点

    // 处理 Vue Scoped CSS 的 data-v- 属性,确保样式不丢失!
    const dataAttrs = Array.from(el.attributes).filter(attr => attr.name.startsWith('data-v-'))
    dataAttrs.forEach(attr => newEl.setAttribute(attr.name, attr.value))

    // 最后,用新的节点替换掉原来的节点
    el.parentNode?.replaceChild(newEl, el)
  }
}

三、使用方式

在需要的元素上直接使用即可,非常简单!

xml 复制代码
<template>
  <!-- 基础用法:自动检测文本,溢出时用原文提示 -->
  <p v-ellipsis-tooltip class="description">{{ longText }}</p>
  
  <!-- 自定义提示内容 -->
  <p v-ellipsis-tooltip="'这是自定义提示内容'" class="title">{{ title }}</p>
</template>

四、总结与展望

  • 优点

    • 自动化:无需手动判断,节省大量代码。
    • 非侵入性:无溢出时不影响原组件。
    • 保持响应式 :正确处理了 data-v-* 属性,替换后的元素依然享有 Scoped CSS 样式。
  • 可扩展点

    • 支持更多 ElTooltip 的参数(如 placement, effect),可通过指令参数或修饰符实现。
    • 增加 offset, transition 等动画配置。
    • 考虑防抖resize事件,实现响应式适配。

希望这个小小的指令能给你的项目带来巨大的便捷!如果觉得有用,别忘了点赞收藏哦~

相关推荐
xkxnq9 小时前
第六阶段:Vue生态高级整合与优化(第93天)Element Plus进阶:自定义主题(变量覆盖)+ 全局配置与组件按需加载优化
前端·javascript·vue.js
A黄俊辉A10 小时前
vue css中 :global的使用
前端·javascript·vue.js
小码哥_常10 小时前
被EdgeToEdge适配折磨疯了,谁懂!
前端
小码哥_常10 小时前
从Groovy到KTS:Android Gradle脚本的华丽转身
前端
灵感__idea10 小时前
Hello 算法:复杂问题的应对策略
前端·javascript·算法
麦麦鸡腿堡11 小时前
JavaWeb_请求参数,设置响应数据,分层解耦
java·开发语言·前端
Dxy123931021612 小时前
CSS常用样式详解:从基础到进阶的全面指南
前端·css
IT_陈寒12 小时前
SpringBoot自动配置揭秘:5个让开发效率翻倍的隐藏技巧
前端·人工智能·后端
Moment12 小时前
前端工程化 + AI 赋能,从需求到运维一条龙怎么搭 ❓❓❓
前端·javascript·面试
Joker Zxc12 小时前
【前端基础(Javascript部分)】6、用JavaScript的递归函数和for循环,计算斐波那契数列的第 n 项值
开发语言·前端·javascript