Vue3 + Element Plus 输入框省略号插件:零侵入式全局解决方案
🚀 Vue3 + Element Plus 输入框省略号插件:零侵入式全局解决方案
📖 前言
在日常开发中,我们经常会遇到输入框内容过长需要显示省略号的需求。传统的做法是在每个组件中手动添加样式和逻辑,但这种方式存在以下问题:
- 重复代码:每个输入框都要写一遍相同的逻辑
- 维护困难:样式分散在各个组件中,难以统一管理
- 容易遗漏:新增输入框时容易忘记添加省略号功能
- 性能问题:每个组件都要单独处理,没有统一的优化
今天我将分享一个零侵入式的全局解决方案,通过 Vue3 插件的方式,自动为所有 `el-input` 输入框添加省略号显示和悬浮提示功能。
🎯 功能特性
- ✅ 完全自动化:无需在任何组件中手动添加代码
- ✅ 智能监听:自动处理动态添加的输入框
- ✅ 性能优化:使用 WeakSet 避免重复处理
- ✅ 类型安全:完整的 TypeScript 支持
- ✅ 内存友好:完善的事件监听器清理机制
- ✅ 响应式:支持窗口大小变化时重新计算
🛠️ 技术实现
核心思路
我们的解决方案基于以下几个核心技术:
- MutationObserver:监听 DOM 变化,自动处理动态添加的输入框
- WeakSet:记录已处理的元素,避免重复处理
- Vue3 插件系统:通过插件方式全局注册功能
- 事件委托:统一管理事件监听器
完整代码实现
/**
* el-input 省略号全局插件
* 自动为所有 el-input 输入框添加省略号显示和悬浮提示功能
* 不包含 textarea 类型
*/
class InputEllipsisManager {
private observer: MutationObserver | null = null
private processedElements = new WeakSet<HTMLElement>()
constructor() {
this.init()
}
init() {
// 等待 DOM 加载完成后开始处理
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => this.startObserving())
} else {
this.startObserving()
}
}
private startObserving() {
// 处理已存在的元素
this.processExistingElements()
// 创建 MutationObserver 监听 DOM 变化
this.observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.type === 'childList') {
mutation.addedNodes.forEach((node) => {
if (node.nodeType === Node.ELEMENT_NODE) {
this.processElement(node as HTMLElement)
}
})
}
})
})
// 开始观察
this.observer.observe(document.body, {
childList: true,
subtree: true
})
}
private processExistingElements() {
// 处理页面中已存在的所有 el-input
const inputs = document.querySelectorAll('.el-input:not(.el-textarea)')
inputs.forEach(input => this.processElement(input as HTMLElement))
}
private processElement(element: HTMLElement) {
// 如果已经处理过,跳过
if (this.processedElements.has(element)) {
return
}
// 查找 el-input 元素
const inputs = element.classList?.contains('el-input') && !element.classList?.contains('el-textarea')
? [element]
: Array.from(element.querySelectorAll?.('.el-input:not(.el-textarea)') || [])
inputs.forEach(inputEl => {
if (this.processedElements.has(inputEl)) {
return
}
this.processedElements.add(inputEl)
this.addEllipsisToInput(inputEl)
})
}
private addEllipsisToInput(inputEl: HTMLElement) {
const inputInner = inputEl.querySelector('.el-input__inner') as HTMLInputElement
if (!inputInner || inputInner.tagName.toLowerCase() === 'textarea') {
return
}
// 添加省略号样式
inputInner.style.textOverflow = 'ellipsis'
inputInner.style.whiteSpace = 'nowrap'
inputInner.style.overflow = 'hidden'
// 创建更新提示的函数
const updateTooltip = () => {
const text = inputInner.value || inputInner.placeholder || ''
if (text && inputInner.scrollWidth > inputInner.clientWidth) {
inputInner.title = text
} else {
inputInner.removeAttribute('title')
}
}
// 添加事件监听器
const events = ['input', 'focus', 'blur', 'change']
events.forEach(eventType => {
inputInner.addEventListener(eventType, updateTooltip)
})
// 初始检查
updateTooltip()
// 监听窗口大小变化
const resizeHandler = () => {
setTimeout(updateTooltip, 100)
}
window.addEventListener('resize', resizeHandler)
// 保存清理函数
;(inputEl as any)._ellipsisCleanup = () => {
events.forEach(eventType => {
inputInner.removeEventListener(eventType, updateTooltip)
})
window.removeEventListener('resize', resizeHandler)
}
}
// 公共方法:手动刷新所有输入框的省略号状态
public refreshInputEllipsis() {
this.processExistingElements()
}
// 销毁方法
public destroy() {
if (this.observer) {
this.observer.disconnect()
}
// 清理所有已处理元素的事件监听器
document.querySelectorAll('.el-input').forEach(inputEl => {
if ((inputEl as any)._ellipsisCleanup) {
;(inputEl as any)._ellipsisCleanup()
delete (inputEl as any)._ellipsisCleanup
}
})
}
}
// 创建全局实例
let ellipsisManager: InputEllipsisManager | null = null
// Vue 插件定义
export default {
install(app: any) {
// 在应用挂载后启动
app.mixin({
mounted() {
if (!ellipsisManager) {
ellipsisManager = new InputEllipsisManager()
}
}
})
// 提供全局方法
app.config.globalProperties.\$refreshInputEllipsis = () => {
if (ellipsisManager) {
ellipsisManager.refreshInputEllipsis()
}
}
}
}
// 导出管理器类(可选,用于高级用法)
export { InputEllipsisManager }
关键代码解析
1. MutationObserver 监听 DOM 变化
this.observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.type === 'childList') {
mutation.addedNodes.forEach((node) => {
if (node.nodeType === Node.ELEMENT_NODE) {
this.processElement(node as HTMLElement)
}
})
}
})
})
作用:自动监听页面中新增的 DOM 元素,确保动态添加的输入框也能被处理。
2. WeakSet 避免重复处理
private processedElements = new WeakSet<HTMLElement>()
if (this.processedElements.has(element)) {
return
}
this.processedElements.add(element)
作用:使用 WeakSet 记录已处理的元素,避免重复处理同一个输入框,提高性能。
3. 智能省略号检测
const updateTooltip = () => {
const text = inputInner.value || inputInner.placeholder || ''
if (text && inputInner.scrollWidth > inputInner.clientWidth) {
inputInner.title = text
} else {
inputInner.removeAttribute('title')
}
}
作用:通过比较 `scrollWidth` 和 `clientWidth` 来判断内容是否超出,只有超出时才显示悬浮提示。
📦 安装使用
1. 创建插件文件
将上述代码保存为 `src/plugins/inputEllipsis.ts`
2. 在 main.js 中注册插件
import { createApp } from 'vue'
import App from '@/App.vue'
import inputEllipsisPlugin from '@/plugins/inputEllipsis'
const app = createApp(App)
app
.use(inputEllipsisPlugin) // 注册输入框省略号插件
.mount('#app')
3. 添加全局样式(可选)
// src/styles/element-plus.scss
// el-input 省略号全局样式
.el-input:not(.el-textarea) {
.el-input__inner {
// 确保省略号正确显示
&[style*=\"text-overflow: ellipsis\"] {
display: block;
width: 100%;
box-sizing: border-box;
}
}
// 为只读状态的输入框也支持省略号
&.is-disabled .el-input__inner {
&[style*=\"text-overflow: ellipsis\"] {
cursor: default;
}
}
}
// 确保输入框容器支持省略号
.el-input__wrapper {
overflow: hidden;
}
🎨 使用效果
安装插件后,所有的 `el-input` 都会自动添加省略号功能:
<template>
<!-- 这些输入框会自动添加省略号功能 -->
<el-input v-model=\"value1\" placeholder=\"自动添加省略号\" />
<el-input v-model=\"value2\" placeholder=\"这个也会自动处理\" />
<!-- textarea 不会被影响 -->
<el-input type=\"textarea\" v-model=\"value3\" placeholder=\"这是文本域,不会被处理\" />
<!-- 动态添加的输入框也会被自动处理 -->
<el-input v-if=\"showInput\" v-model=\"value4\" placeholder=\"动态输入框也会被处理\" />
</template>
功能演示
- ✅ 内容超出时显示省略号
- ✅ 鼠标悬浮时显示完整内容
- ✅ 支持输入内容变化时动态更新
- ✅ 支持窗口大小变化时重新计算
- ✅ 自动排除 textarea 类型
🔧 高级用法
手动刷新省略号状态
// 在任何组件中
this.\$refreshInputEllipsis()
获取管理器实例
import { InputEllipsisManager } from '@/plugins/inputEllipsis'
// 创建自定义实例
const customManager = new InputEllipsisManager()
🚀 性能优化
1. 防抖处理
const resizeHandler = () => {
setTimeout(updateTooltip, 100)
}
窗口大小变化时使用防抖,避免频繁计算。
2. 事件监听器清理
;(inputEl as any)._ellipsisCleanup = () => {
events.forEach(eventType => {
inputInner.removeEventListener(eventType, updateTooltip)
})
window.removeEventListener('resize', resizeHandler)
}
每个输入框都保存清理函数,避免内存泄漏。
3. WeakSet 优化
使用 WeakSet 而不是 Set,让垃圾回收器自动清理不再使用的元素引用。
🎯 适用场景
- ✅ 管理系统:大量表单输入框
- ✅ 数据展示:表格中的输入框
- ✅ 动态表单:根据条件动态生成的输入框
- ✅ 组件库:需要统一处理输入框样式的项目
🔍 技术亮点
- 零侵入式:无需修改任何现有组件代码
- 自动化:完全自动处理,无需手动干预
- 高性能:使用现代浏览器 API 优化性能
- 类型安全:完整的 TypeScript 支持
- 内存友好:完善的内存管理机制
📝 总结
这个输入框省略号插件通过 Vue3 插件系统、MutationObserver 和 WeakSet 等技术,实现了一个完全自动化的解决方案。它不仅解决了传统方案的痛点,还提供了更好的性能和用户体验。
核心优势:
- 🚀 零侵入:安装即用,无需修改现有代码
- 🎯 自动化:智能处理所有输入框
- ⚡ 高性能:优化的算法和内存管理
- 🛡️ 类型安全:完整的 TypeScript 支持
如果您觉得这个方案有用,欢迎点赞收藏!也欢迎在评论区分享您的使用心得和改进建议。
作者简介:专注于前端技术分享,Vue3 + TypeScript 实践者
技术栈:Vue3, TypeScript, Element Plus, 前端工程化