el-table数据列内容太多时showOverflowTooltip闪烁抖动不显示问题

1,322 阅读2分钟

问题描述(show-overflow-tooltip)

  1. 表格某一列内容超长时,鼠标悬浮时会闪烁抖动,显示不出悬浮弹框

问题原因分析:

  1. showOverflowTooltip执行了td鼠标移入mouseenter、鼠标移出mouseleave方法

  2. 通过控制台,可以看到,当鼠标移入时,会不停的打印移入移出,其实我就移入了一次

image.png

  1. 原因是当鼠标移入时,本来已经显示了弹框,但是由于内容超长,弹框内容撑开鼠标又被移出了,触发了移出方法,就隐藏了弹框,这个过程很短暂,以至于看不到
  2. 由于el-table列td的mouseenter、mouseleave方法都没有设置延迟,所以很容易在触发移入的时候也触发了移出

解决思路:

  1. td的mouseenter设置延迟200ms再显示tooltip弹框,修改handleCellMouseEnter方法
if (
    (rangeWidth + padding > cellChild.offsetWidth ||
      cellChild.scrollWidth > cellChild.offsetWidth) &&
    this.$refs.tooltip
  ) {
    const tooltip = this.$refs.tooltip
    setTimeout(() => {
      if (tooltip.showPopper) {
        return
      }
      // TODO 会引起整个 Table 的重新渲染,需要优化
      ...
    }, 201)
  }
  1. td的mouseleave设置延迟200ms再关闭tooltip弹框,修改handleCellMouseLeave方法
if (tooltip) {
    //tooltip.setExpectedState(false)
    //tooltip.handleClosePopper()
    // hide方法调用了setExpectedState(false)、debounceClose方法,debounceClose带有200ms的抖动延迟再执行handleClosePopper
    tooltip.hide()
  }
  1. 其他方式:el-popover代替 show-overflow-tooltip
  2. 其他方式:重写el-tooltip,代替show-overflow-tooltip,思路是鼠标移入时计算内容宽度和当前元素宽度,如果满足: 内容真实渲染宽度>元素的实际宽度或者实际内容的宽度(包括由于溢出而无法展示在网页的不可见部分)>元素的实际宽度,就显示tooltip,不满足就禁用tooltip
<template>
  <el-tooltip
    class="item"
    effect="dark"
    placement="top-start"
    :disabled="!isShowTooltip"
  >
    <div
      slot="content"
      class="common-custom-tooltips"
      v-html="hoverTitle"
    ></div>
    <span
      :id="id"
      class="overflow-tooltip"
      @mouseenter="onMouseOver"
      v-html="content"
    ></span>
  </el-tooltip>
</template>

<script>
export default {
  name: 'OverflowTooltip',
  props: {
    content: [String, Number, Boolean],
    title: [String, Number, Boolean]
  },
  data() {
    return {
      hoverTitle: '',
      id: Math.random().toString(36).slice(2),
      isShowTooltip: false
    }
  },
  methods: {
    onMouseOver() {
      const el = document.getElementById(this.id)
      const elComputed = document.defaultView.getComputedStyle(el, '')
      const padding =
        parseInt(elComputed.paddingLeft.replace('px', '')) +
        parseInt(elComputed.paddingRight.replace('px', ''))

      const range = document.createRange()
      range.setStart(el, 0)
      range.setEnd(el, el.childNodes.length)
      const rangeWidth = range.getBoundingClientRect().width
      this.isShowTooltip =
        rangeWidth + padding > el.offsetWidth || el.scrollWidth > el.offsetWidth
      if (this.isShowTooltip) {
        this.hoverTitle = this.title || this.content
      }
    }
  }
}
</script>

<style scoped>
.overflow-tooltip {
  display: inline-block;
  width: 100%;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  vertical-align: middle;
}
</style>

找到原因了,就能从根本解决问题,element没有考虑到超长内容的情况,也算是他们的一个bug吧