Display ellipsis and tooltip when the text is too long, encapsulate tooltip

Table of contents

Application scenario:

parent component:

Subassembly:

bug:


Application scenario:

Many places in the project need to display some field information, such as project information and project description fields. There is always a need to display when there are too many fields, add an ellipsis to display, and then display tooltip. This function is easy to implement in el-table , just show-overflow-tooltip can be realized, because it needs to be used in many places, so this function is encapsulated, there are two implementation methods, adapting elementUI and element-plus. Look at the end first!


parent component:

Since it is packaged, first create a new file, such as: ToolTip.vue, as the packaged page, and then introduce this component in the parent component. The introduction requires some information. Since it is a packaged tooltip, the content, orientation, and There is a ref name for easy distinction. As follows, it is best for the parent component to have a style on the outer layer to facilitate fixed width.

<div class="title">
    <ToolTip :content="projectName" placement="bottom" ref-name="tooltipOver"></ToolTip>
</div>

Subassembly:

el-tooltip has an attribute disabled, which determines whether to disable the tooltip by judging whether the content needs to display an ellipsis.

 The whole code is as follows:

<template>
  <div class="text-tooltip">
    <el-tooltip class="text-truncate" effect="dark" :disabled="isShowTooltip" :content="content" placement="top">
      <p class="over-flow" :class="className" @mouseover="onMouseOver(refName)">
        <span :ref="refName" class="ellipsis">{
   
   { content || '' }}</span>
      </p>
    </el-tooltip>
  </div>
</template>

<script>
export default {
  name: 'textTooltip',
  props: {
    // 显示的文字内容
    content: {
      type: String,
      default: () => {
        return ''
      }
    },
    // 外层框的样式,在传入的这个类名中设置文字显示的宽度
    className: {
      type: String,
      default: () => {
        return ''
      }
    },
    // 为页面文字标识(如在同一页面中调用多次组件,此参数不可重复)
    refName: {
      type: String,
      default: () => {
        return ''
      }
    }
  },
  data() {
    return {
      isShowTooltip: true
    }
  },
  mounted() {
//判断宽度是否需要出现toooltip
    this.checkTooltipVisibility()
//优化resize
    window.addEventListener('resize', this.checkTooltipVisibility)
  },
  beforeUnmount() {
    window.removeEventListener('resize', this.checkTooltipVisibility)
  },
  methods: {
    onMouseOver(refName) {
//这里的refName是子组件的refName不是从父组件传来的,所以需要在@mouseover里传递,使得页面能找到这个dom
      let parentWidth = this.$refs[refName].parentNode.offsetWidth
      let contentWidth = this.$refs[refName].offsetWidth
      // 判断是否开启tooltip功能
      if (contentWidth > parentWidth) {
        this.isShowTooltip = false
      } else {
        this.isShowTooltip = true
      }
    },
    checkTooltipVisibility() {
      const spanEl = this.$refs[this.refName]
      if (spanEl) {
        const parentWidth = spanEl.parentNode.offsetWidth
        const contentWidth = spanEl.offsetWidth
        this.isShowTooltip = contentWidth > parentWidth
      }
    }
  }
}
</script>

<style lang="scss" scoped>
.over-flow {
  overflow: hidden;
  white-space: nowrap;
  width: 100%; /* 设置父元素的宽度 */
}
.ellipsis {
  width: 100%; /* 设置子元素的宽度,确保父元素的宽度能容纳子元素*/
  white-space: nowrap; /* 不换行 */
  overflow: hidden; /* 溢出隐藏 */
  text-overflow: ellipsis; /* 添加省略号 */
}
//这里还可以将外层的className对应的class写在这里
p {
  margin: 0;
}
</style>

Note: When the width of the parent element to which the style is applied .over-flowis not enough to accommodate the child element, the overflow part of the child element will be hidden, and the ellipsis may not be displayed. This is also the reason why I have been modifying before but the style still cannot be rendered. Later, I set the width of the child element and the parent element to 100% (the specific value is also possible) and it succeeded. The effect is as follows:

The details of the element are as follows. If it does not take effect, you can check whether it is consistent with my problem. 

In this way, when the page width changes, it can also be recalculated and then display the ellipsis or not.

Of course, calculating the width of the dom is a method, and it can also be displayed by calculating the content length of the content, such as how many characters there are (this method has been used before, and it has to be used in some places. there is no fixed width there)

The former method is obviously better. This method can replace span with el-text in element-ui, which is more convenient and does not need to consider style issues, as follows:

 <span :ref="refName" class="ellipsis">{
   
   { content || '' }}</span>




//换成el-text
 <el-text :ref="refName" truncated>{
   
   { content || '' }}</el-text>

 but! element-plus still discards el-text, the page cannot parse this component, and the ellipsis cannot be displayed on the page after packaging!

bug:

On the same day, I found that the tooltip could not be displayed after writing this component. The reason is very simple. The innermost span cannot overflow the width of <p>, so according to this situation, I need to meet two requirements:

1 is that the child element needs to be able to overflow the parent element in width,

2 is to display the tooltip when overflowing (calculated overflow, then the width of the child element needs to be greater than the parent element) and ellipsis

Look at 2 first. It is required to display an ellipsis, so the width of the child element needs to be within the width of the parent element. This is also mentioned in the code, but I need to meet the requirement 1, so the two requirements conflict.

Solution 1: Change the style. When the component is initialized, first change the style to style 1 (the style mentioned above) that cannot overflow but displays an ellipsis, and change it to style 2 that can overflow when the mouse moves up. When the mouse moves out, change to style 1

 <template>
  <div class="text-tooltip">
    <el-tooltip class="item" effect="dark" :disabled="isShowTooltip" :content="content" placement="top">
      <div class="over-flow" :class="className" @mouseover="onMouseOver(refName)" @mouseout="onMouseOut(refName)">
        <span :ref="refName" class="ellipsis">{
   
   { content || '' }}</span>
      </div>
    </el-tooltip>
  </div>
</template>



methods: {
    onMouseOver(refName) {
      //更换样式为子元素可以溢出父元素的样式
      this.$refs[refName].style.removeProperty('width')
      this.$refs[refName].style.overflow = 'visible'
      this.$refs[refName].style.whiteSpace = 'nowrap'
      this.$refs[refName].style.textOverflow = 'ellipsis'
      this.$refs[refName].parentNode.style.overflow = 'hidden'
      this.$refs[refName].parentNode.style.width = '100%'
      let parentWidth = this.$refs[refName].parentNode.offsetWidth
      let contentWidth = this.$refs[refName].offsetWidth
      // 判断是否开启tooltip功能
        this.isShowTooltip = true
      }
    },
    onMouseOut(refName) {
      // 重置样式为省略文本
      this.$refs[refName].style.overflow = 'hidden'
      this.$refs[refName].style.width = '100%'
      this.$refs[refName].style.whiteSpace = 'nowrap'
      this.$refs[refName].style.textOverflow = 'ellipsis'
      this.$refs[refName].parentNode.style.overflow = 'visible'
      this.$refs[refName].parentNode.style.width = '100%'
    },
    checkTooltipVisibility() {
      const spanEl = this.$refs[this.refName]
      if (spanEl) {
        //初始样式为省略文本
        this.onMouseOut(this.refName)
        const parentWidth = spanEl.parentNode.offsetWidth
        const contentWidth = spanEl.offsetWidth
        if (contentWidth > parentWidth) {
          this.isShowTooltip = false
        } else {
          this.isShowTooltip = true
        }
      }
    }
  }


<style lang="scss" scoped>
//初始的省略显示
.over-flow {
  overflow: visible; /* 溢出隐藏 */
  white-space: nowrap;
  width: 100%; /* 设置父元素的宽度 */
}
.ellipsis {
  // width: 100%; /* 设置子元素的宽度,确保父元素的宽度能容纳子元素*/
  white-space: nowrap; /* 不换行 */
  overflow: hidden; /* 可以溢出 */
  text-overflow: ellipsis; /* 添加省略号 */
}

div {
  margin: 0;
}

Solution 2 : Do not calculate directly , display all tooltips, which saves trouble, span display style 1


    <el-tooltip class="item" effect="dark" :disabled="!isShowTooltip" :content="content" placement="top">
      <div class="over-flow" :class="className">
        <span :ref="refName" class="ellipsis">{
   
   { content || '' }}</span>
      </div>
    </el-tooltip>


<style lang="scss" scoped>
//初始的省略显示
.over-flow {
  overflow: hidden; /* 溢出隐藏 */
  white-space: nowrap;
  width: 100%; /* 设置父元素的宽度 */
}
.ellipsis {
  width: 100%; /* 设置子元素的宽度,确保父元素的宽度能容纳子元素*/
  white-space: nowrap; /* 不换行 */
  overflow: hidden; /* 溢出隐藏 */
  text-overflow: ellipsis; /* 添加省略号 */
}

To sum up. I really don't know if there are other good solutions. Can anyone who knows the comment area give me some guidance?

Guess you like

Origin blog.csdn.net/ParkChanyelo/article/details/131063872