🔥 我封装了一个会“思考”的指令!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事件,实现响应式适配。

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

相关推荐
Dragon Wu21 分钟前
前端 下载后端返回的二进制excel数据
前端·javascript·html5
北海几经夏27 分钟前
React响应式链路
前端·react.js
晴空雨1 小时前
React Media 深度解析:从使用到 window.matchMedia API 详解
前端·react.js
一个有故事的男同学1 小时前
React性能优化全景图:从问题发现到解决方案
前端
探码科技1 小时前
2025年20+超实用技术文档工具清单推荐
前端
Juchecar1 小时前
Vue 3 推荐选择组合式 API 风格(附录与选项式的代码对比)
前端·vue.js
uncleTom6661 小时前
# 从零实现一个Vue 3通用建议选择器组件:设计思路与最佳实践
前端·vue.js
影i1 小时前
iOS WebView 异步跳转解决方案
前端
Nicholas681 小时前
flutter滚动视图之ScrollController源码解析(三)
前端
爪洼守门员1 小时前
安装electron报错的解决方法
前端·javascript·electron