Implement a content over display ellipsis and hover over to display toolTip, not over display toolTip component

Ps: This component is based on element-Plus, implemented using vue3’s latest Setup syntax sugar. If you are not clear, you can use other technology stacks according to my ideas.

background

There are many places in the project that go beyond the need to display ellipses and then hover over to display tooltips. Before this, I noticed that some of the projects that are mouse floats in all show tooltip, regardless of whether it’s over; Others go beyond the ellipsis and don’t include tooltips, which is where the user doesn’t even know the full information. I feel that this should not be the desired effect of the product. Maybe there are too many demands before, or too many people have handled this project, so we didn’t pay attention to this subtle function. Then I took advantage of the idle period of this version iteration to tidy up, looking for products one by one, in order to unify and improve this function in the project. The main technology stack for the project is VUE2, which encapsulates a component in the project. Here, I want to use vue3+ element-Plus implementation to clean up your mind and consolidate and learn the new VUe3 setup syntax sugar.

The function point

  • Beyond displays ellipsis
  • Show ellipsis case, mouse over to show all
  • Consider customizing the content area if it is not plain text
  • Consider that the content displayed in tooltip is customizable

implementation

  • Beyond the ellipsis display this actually need not say much, we directly use CSS to achieve good, is the common old three, plus the width of the limit.

    <template>
      <div class="content" :style="{width: props.width}">
        {{props.content}}
      </div>
    </template>
    <script setup lang="ts">
      // Define the type of props
      interface props {
        content: string,
        width: string
      }
      // Use withDefaults to give props a default value
      const props = withDefaults(defineProps<props>(), {
        content: ' '.width: ' '
      })
    </script>
    <style>
      .content {
        overflow: hidden; 
        white-space: nowrap;
        text-overflow: ellipsis
      }
    </style>
    Copy the code

    This now allows you to override the ellipsis. Let’s call it to see what happens:

Component calling code

<script setup lang="ts">
  // This starter template is using Vue 3 <script setup> SFCs
  // Check out https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup
  // import HelloWorld from './components/HelloWorld.vue'
  import { reactive } from 'vue';
  import ShowTooltip from './showTooltip.vue';
  const content = reactive({
    data: 'Hello hello hello hello hello hello hello hello hello hello hello hello hello hello'
  })
</script>

<template>
  <ShowTooltip :content="content.data" width="200px"/>
</template>
Copy the code

I don’t know. It smells good after I use it. Component automatic registration, just import. Instead of writing setup Return separately, templates can be used directly. Props has a separate interface, and the previous context also separates attrs and emit… If you are interested, you can try it. So let’s get back to our component writing.

  • Show ellipsis case, mouse over to show all

    • The first step is to use the el-ToolTip component from Element-Plus.

      <template>
        <el-tooltip
          effect="dark"
          :content="props.content"
          placement="top"
        >
          <div class="content" :style="{width: props.width}">
            {{props.content}}
          </div>
        </el-tooltip>
      </template>
      <script setup lang="ts">
        // Define the type of props
        interface props {
          content: string,
          width: string
        }
        // Use withDefaults to give props a default value
        const props = withDefaults(defineProps<props>(), {
          content: ' '.width: ' '
        })
      </script>
      <style>
        .content {
          overflow: hidden; 
          white-space: nowrap;
          text-overflow: ellipsis
        }
      </style>
      Copy the code

      Now only the mouse is implemented to show the tooltip and does not distinguish whether it is exceeded or not.

    • Implement beyond to display tooltip

      So let’s think about how to tell if it exceeds. It’s not hard to imagine that we can compare the width of the content with the width of the outer box. When the width of the content is greater than or equal to the width of the box, the tooltip is displayed. We can make use of the SPAN tag that is not affected by CSS styles, the width of the content is automatically stretched, so we can wrap the content around the SPAN tag, and then calculate the width, without further words, directly into the code.

        <template>
          <el-tooltip
            effect="dark"
            :content="props.content"
            placement="top"
            :disabled="isShow"
          >
            <div class="content" :style="{width: props.width}" @mouseover="isShowTooltip">
              <span ref="contentRef">{{props.content}}</span>
            </div>
          </el-tooltip>
        </template>
        <script setup lang="ts">
          import { ref } from 'vue'
          // Define the type of props
          interface props {
            content: string,
            width: string
          }
          // Use withDefaults to give props a default value
          const props = withDefaults(defineProps<props>(), {
            content: ' '.width: ' '
          })
          // Use isShow to control whether the tooltip is displayed
          let isShow = ref<boolean>(true)
          // Define a ref on the span tag
          const contentRef  = ref()
          const isShowTooltip = function () :void {
            // Calculate the offsetWidth of the span tag and the offsetWidth of the box element, and assign isShow
            if(contentRef.value.parentNode.offsetWidth > contentRef.value.offsetWidth) {
              isShow.value = true
            } else {
              isShow.value = false}}</script>
        <style>
          .content {
            overflow: hidden; 
            white-space: nowrap;
            text-overflow: ellipsis
          }
        </style>
      Copy the code

      At this point, we’re good enough to display text content, and we’re halfway there.

  • Consider the case of not plain text, you can customize the content area actually to this step is relatively simple, is write slot.

      <template>
        <el-tooltip
          effect="dark"
          :content="props.content"
          placement="top"
          :disabled="isShow"
        >
          <div class="content" :style="{width: props.width}" @mouseover="isShowTooltip">
            <span ref="contentRef">
              <slot name="content">{{props.content}}</slot>
            </span>
          </div>
        </el-tooltip>
      </template>
    Copy the code

    call

      <ShowTooltip :content="content.data" width="200px">
        <template v-slot:content>1212324323</template>
      </ShowTooltip>
    Copy the code

    The main reason to consider content as a slot is because of the presence in the project: listing values in the form of tags beyond the tooltip display. I’m going to do a little bit of a reverse here.

      <script setup lang="ts">
        // This starter template is using Vue 3 <script setup> SFCs
        // Check out https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup
        // import HelloWorld from './components/HelloWorld.vue'
        import { reactive } from 'vue';
        import ShowTooltip from './showTooltip.vue';
        const content = reactive({
          data: 'Hello hello hello hello hello hello hello hello hello hello hello hello hello hello'
        })
        const tags = reactive([
          'apple'.'pear'.'banana'.'mango..'Pitaya'.'Kiwi'
        ])
      </script>
    
      <template>
        <! -- Simple text -->
        <ShowTooltip :content="content.data" width="200px"/>
      <br/>
        <! Customize the content -->
        <ShowTooltip :content="content.data" width="200px">
          <template v-slot:content>
            <el-tag v-for="item in tags" :key="item" class="tag-item"> {{item}}</el-tag>
          </template>
        </ShowTooltip>
      </template>
    
      <style>
        .tag-item {
          margin-left: 5px;
        }
      </style>
    
    Copy the code

  • Consider tooltip display content can be customized to take the same approach as above, will customize the area slot, and compatible with both tooltipContent and Content. Go straight to code

      <template>
        <el-tooltip
          effect="dark"
          :content="props.tooltipContent ? props.tooltipContent : props.content"
          placement="top"
          :disabled="isShow"
        >
          <template #content>
            <! TooltipContent -->
            <slot name="tooltipContent">{{props.tooltipContent ? props.tooltipContent : props.content}}</slot>
          </template>
          <div class="content" :style="{width: props.width}" @mouseover="isShowTooltip">
            <span ref="contentRef">
              <! -- Give a default value with no write slot, compatible with plain text -->
              <slot name="content">{{props.content}}</slot>
            </span>
          </div>
        </el-tooltip>
      </template>
      <script setup lang="ts">
        import { ref } from 'vue'
        // Define the type of props
        interface props {
          content: string,
          width: string, tooltipContent? : string }// Use withDefaults to give props a default value
        const props = withDefaults(defineProps<props>(), {
          content: ' '.width: ' '.tooltipContent: ' '
        })
        // Use isShow to control whether the tooltip is displayed
        let isShow = ref<boolean>(true)
        // Define a ref on the span tag
        const contentRef  = ref()
        const isShowTooltip = function () :void {
          // Calculate the offsetWidth of the span tag and the offsetWidth of the box element, and assign isShow
          if(contentRef.value.parentNode.offsetWidth > contentRef.value.offsetWidth) {
            isShow.value = true
          } else {
            isShow.value = false}}</script>
      <style>
        .content {
          overflow: hidden; 
          white-space: nowrap;
          text-overflow: ellipsis
        }
      </style>
    Copy the code

    call

      <ShowTooltip width="200px">
        <template v-slot:tooltipContent>
          <span>1223214234</span>
        </template>
        <template v-slot:content>
          <el-tag v-for="item in tags" :key="item" class="tag-item"> {{item}}</el-tag>
        </template>
      </ShowTooltip>
    Copy the code

summary

This component relies on a few attributes passed in and slots thrown.

attribute
  • Width: the width of the box to use beyond display… , this attribute is mandatory
  • Content: indicates the text content
  • TooltipContent: Displays the text content displayed in toolTip. If this attribute is not passed, the content is displayed
slot
  • Content: Content slot, custom content area
  • TooltipContent: ToolTip content custom area
Component complete code
<template>
  <el-tooltip
    effect="dark"
    :content="props.tooltipContent ? props.tooltipContent : props.content"
    placement="top"
    :disabled="isShow"
  >
    <template #content>
      <slot name="tooltipContent">{{props.tooltipContent ? props.tooltipContent : props.content}}</slot>
    </template>
    <div class="content" :style="{width: props.width}" @mouseover="isShowTooltip">
      <span ref="contentRef">
        <! -- Give a default value with no write slot, compatible with plain text -->
        <slot name="content">{{props.content}}</slot>
      </span>
    </div>
  </el-tooltip>
</template>
<script setup lang="ts">
  import { ref, useSlots } from 'vue'
  // Define the type of propsinterface props { content? : string,width: string, tooltipContent? : string }// Use withDefaults to give props a default value
  const props = withDefaults(defineProps<props>(), {
    content: ' '.width: ' '.tooltipContent: ' '
  })
  // Use isShow to control whether the tooltip is displayed
  let isShow = ref<boolean>(true)
  // Define a ref on the span tag
  const contentRef  = ref()
  const isShowTooltip = function () :void {
    // Calculate the offsetWidth of the span tag and the offsetWidth of the box element, and assign isShow
    if(contentRef.value.parentNode.offsetWidth > contentRef.value.offsetWidth) {
      isShow.value = true
    } else {
      isShow.value = false}}</script>
<style>
  .content {
    overflow: hidden; 
    white-space: nowrap;
    text-overflow: ellipsis
  }
</style>
Copy the code

On a side note: you can do a lot more with this depending on your needs, such as click trigger, mouse over trigger tooltip, etc