实现 ElTable 超长显示 … 并且鼠标移入有tooltip
最近做了个需求要求在table中不允许折行,超长通过“...”显示,并且鼠标移入的时候有 tooltip 显示完整信息。
1.背景
- 由于项目开始比较早,使用的 elementPlus 版本为 2.2.15,此时的elementplus 还不支持,控制单个 tableColums 显示tooltip(目前最新的elementPlus实现了这个功能)。
2.实现
做了大量调研,发现最好的办法就是通过一个新的节点去和tablecolums做比较判断,是否显示tooltip
方法一
- 在渲染table的时候对tableColums做封装,使用elTooltip包一层,新建一个节点,和tableColums做判断。刚开始这个方法已经实现,用了一段时间,随着数据量的变大,发现这种方法导致table渲染很慢,接口数据回来两秒之后才能出了table(前提是tableTree或者一页200条数据)。所以萌生出了做优化的想法,也就出了方法二。
方法二
-
现在我们定的方案是在table渲染完再做tooltip的判断
-
使用指令的方法 在 mouseover 的时候判断是否渲染。下面先看代码。
-
引入第三方组件库,我用的是这个版本 “@popperjs/core”: “^2.11.8”
pnpm i @popperjs/core
-
先新建指令
v-overflowTooltip
/** * @description: 溢出文本提示 */ import type { App, Directive, DirectiveBinding } from 'vue' import { createPopper } from '@popperjs/core' import { useZIndex } from 'element-plus/es/hooks/use-z-index/index' // tooltip 下方小三角 function renderArrow() { const arrow = document.createElement('div') arrow.className = 'el-popper__arrow' return arrow } // tooltip 正文部分 function renderContent(value) { const { nextZIndex } = useZIndex() const content = document.createElement('div') content.className = 'el-popper is-light table-tooltip_text table-tooltip' content.innerHTML = value content.style.zIndex = String(nextZIndex()) document.body.appendChild(content) return content } // 生命周期 先通过css 设置超长的...显示 const created = (el) => { el.style.overflow = 'hidden' el.style.textOverflow = 'ellipsis' el.style.whiteSpace = 'nowrap' } // 获取 tableColums 的上下左右 padding const getPadding = (el: HTMLElement) => { const style = window.getComputedStyle(el, null) const paddingLeft = Number.parseInt(style.paddingLeft, 10) || 0 const paddingRight = Number.parseInt(style.paddingRight, 10) || 0 const paddingTop = Number.parseInt(style.paddingTop, 10) || 0 const paddingBottom = Number.parseInt(style.paddingBottom, 10) || 0 return { left: paddingLeft, right: paddingRight, top: paddingTop, bottom: paddingBottom } } const mounted = (el, binding: DirectiveBinding<any>) => { let removePopperTime: any = null const createTooltip = () => { // 创建新的节点用作参照物,判断是否渲染 tooltip const range = document.createRange() range.setStart(el, 0) range.setEnd(el, el.childNodes.length) const rangeWidth = range.getBoundingClientRect().width const rangeHeight = range.getBoundingClientRect().height const { top, left, right, bottom } = getPadding(el) const horizontalPadding = left + right const verticalPadding = top + bottom if ( !( rangeWidth + horizontalPadding > el.offsetWidth || rangeHeight + verticalPadding > el.offsetHeight || el.scrollWidth > el.offsetWidth ) ) { return } // 判断当前元素有没有未删除的Popper,有则阻止删除并且return if (removePopperTime) { clearTimeout(removePopperTime) removePopperTime = null return } // tooltip 显示的内容 const value = binding.value || el.textContent if (!value) { return } // 创建Popper元素 const content = renderContent(value) // 创建Popper小三角 const arrow = renderArrow() content.appendChild(arrow) // 调用插件,渲染Popper // 还需要配置什么自己去查吧 createPopper(el, content, { strategy: 'absolute', placement: 'top-start', modifiers: [ { name: 'offset', options: { offset: [0, -1] } }, { name: 'arrow', options: { element: arrow, padding: 10 } }, { name: 'showAfter', enabled: true } ] }) // 删除 const removePopper = () => { removePopperTime = setTimeout(() => { try { content && document.body.removeChild(content) el.removeEventListener('mouseout', removePopper) } catch {} clearTimeout(removePopperTime) removePopperTime = null }, 100) } // 移入弹框后取消删除 content.addEventListener('mouseover', () => { clearTimeout(removePopperTime) removePopperTime = null }) // 元素移出 el.addEventListener('mouseout', removePopper) // 弹框移出 content.addEventListener('mouseout', removePopper) } el.addEventListener('mouseover', createTooltip) } const handlerOverflowTooltip: Directive = { created, mounted } export const setupOverflowTooltipDirective = (app: App<Element>) => { app.directive('overflowTooltip', handlerOverflowTooltip) }
-
这样 指令就可以使用啦
-
现在看table中的逻辑吧,,因为我们是对table的二次封装用的tsx,这块主要的问题是,如何绑上指令
// 在tableColums 内容外层 包一个 div 做指令绑定 // resolveDirective withDirectives 是从 vue 导出的 const overflowTooltip = resolveDirective('overflowTooltip') return withDirectives(h('div', { class: 'aaa' }, value), [[overflowTooltip]])
-
现在就可以愉快享用了,祝君好运