引言:会"思考"的指令!
你是否还在为页面上成堆的 el-tooltip
组件而头疼?只为了一行可能溢出、可能不溢出的文本,每个地方都要手动包裹一层,代码又臭又长,性能还不美观。今天,我带大家封装一个"会思考"的 Vue 自定义指令 v-ellipsis-tooltip
。它能让 ElTooltip
变得智能化:只在文本内容溢出时,才自动出现 Tooltip;如果文本完整显示,则什么都不发生。 完美实现"按需展示",让代码更简洁,体验更优雅!"
一、实现思路 & 核心技术点
- 指令的职责 :在元素
mounted
时,判断其内容是否溢出。 - 关键 API :使用
el.scrollHeight > el.clientHeight
检测溢出。 - 灵魂所在 :使用 Vue 3 的
createVNode
和render
函数,动态创建并挂载ElTooltip
组件。 - 优雅替换 :巧用
nextTick
等待渲染完成,并妥善处理原始元素的class
、style
和 Vue 的 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事件,实现响应式适配。
- 支持更多
希望这个小小的指令能给你的项目带来巨大的便捷!如果觉得有用,别忘了点赞收藏哦~