Vue3+element-plus实现v-text-tooltip自定义指令--自动判定是否文本溢出并动态创建el-tooltip

332 阅读2分钟

参考链接:# vue3通过ElementPlus的tooltip组件实现自定义指令文字提示

前言

  • 实际项目中我们往往都希望整个项目的 tooltip 样式应该是保持一致的
  • 然而现实是管理上很难让所有开发人员做到 tooltip 样式一致(特别是没有设计的情况下),有的开发人员不愿意问,也懒得去参考其他地方,或者项目里已经乱了,比如有的地方tooltip是白色的有的地方是黑色的,开发人员也懒得问的情况下,就继续随便搞了,这很常见,也不能怪谁
  • 所以呢,咱们就需要从架构层去考虑和控制避免这种不统一的问题
  • 那在 vue3 项目中,我想到的最直接的方法就是通过【自定义指令】去实现,一来是方便统一管理整个项目的 tooltip,二来呢所有项目里也不需要繁琐得去写 el-tooltip 了,一个指令就能搞定,轻松解决这种不起眼又挺烦人的问题

效果展示

image.png image.png

自定义指令代码在此!!!

import { DirectiveBinding } from 'vue'
import { ElTooltip } from 'element-plus'

/**
 * 判断文本是否溢出
 */
function isTextOverflowing(element) {
  const style = window.getComputedStyle(element)
  const range = document.createRange()
  range.selectNodeContents(element)
  const contentWidth = range.getBoundingClientRect().width
  const containerWidth = parseFloat(style.width)
  return contentWidth > containerWidth
}

/**
 * 创建tooltip,这里采用element-plus的tooltip组件
 * 使用案例:
 * <span v-text-tootip:auto>xxxxxxx</span> tooltip 自定判断文本是否溢出,溢出了鼠标悬浮才会展示tooltip
 * <span v-text-tootip>xxxxxxx</span> tooltip 直接悬浮展示tooltip
 * @param el
 * @param binding
 */
const createTooltip = (el: any, binding: DirectiveBinding) => {
  const arg = binding.arg
  const isShow = arg === 'auto' ? isTextOverflowing(el) : true // binding.value || true
  // 创建组件,显示tooltip
  if (isShow) {
    // 判断是否有根元素,存在,则移除
    const elRoot = document.querySelector('#_tooltip_root')
    if (elRoot) {
      elRoot.remove()
    }
    // 初始化 根元素
    el._tiproot = null
    el._tipapp = null
    const id = '_tooltip_root'
    const _tiproot = document.createElement('div')
    _tiproot.id = id
    // 通过createApp 创建实例组件
    const _tipapp = createApp(ElTooltip, {
      trigger: 'hover',
      virtualRef: el,
      rawContent: true,
      placement: 'top',
      virtualTriggering: true,
      content: el.innerHTML
    })
    el._tiproot = _tiproot
    el._tipapp = _tipapp
    // body添加根元素
    document.body.appendChild(_tiproot)
    // 将新组件挂载到根元素
    if (_tipapp && _tiproot) {
      el._tipapp.mount('#' + id)
    }
  }
}

/**
 * 文本溢出则显示省略号并悬浮鼠标展示tooltip
 */
export const textTootip = (el, binding: DirectiveBinding) => {
  // 文本溢出则展示省略号
  el.style.whiteSpace = 'nowrap'
  el.style.overflow = 'hidden'
  el.style.textOverflow = 'ellipsis'

  // 创建tooltip
  createTooltip(el, binding)
}

注册全局指令

import textTootip from './textTootip'
app.directive('textTootip', textTootip)