封装文字溢出显示全部的组件

68 阅读1分钟

需求背景

需求是实现类似el-table-column的show-tooltip-overflow的功能,文本在内容超出后需要能够hover展示全部

组件设计

组件的基本的dom结构是,一个容器wrap和一个文本text

<div ref="wrapDom" class="show-tooltip-overflow-index"> 
  <div ref="textDom"class="no-overflow-text" :class="lineClamp == 1 ? 'single' : 'multi'" v-if="!isOverflow">{{ text }}</div> 
  <a-tooltip v-else> 
    <template #title>{{ text }}</template> 
    <span :class="lineClamp == 1 ? 'single-overflow-text' : 'multi-overflow-text'">{{ text }}       </span> 
   </a-tooltip> 
   </div>

组件需要能够实现单行和多行两种类型的文字,因此组件需要传入lineClamp属性,用来设置几行溢出显示。

  1. 单行实现,将wrap和text的宽度进行比对, 如果text的宽度的大于wrap的宽度,则说明文字宽度大于容器宽度。
isOverflow.value = textDom.value?.scrollWidth > wrapDom.value?.clientWidth
  1. 多行实现,通过js代码去计算行数,判断行数是否大于lineClamp
const countLines = (target) => {
  var style = window.getComputedStyle(target, null)
  var height = parseInt(style.getPropertyValue("height"))
  var font_size = parseInt(style.getPropertyValue("font-size"))
  var line_height = parseInt(style.getPropertyValue("line-height"))
  var box_sizing = style.getPropertyValue("box-sizing")

  if (isNaN(line_height)) line_height = font_size * 1.2

  if (box_sizing == "border-box") {
    var padding_top = parseInt(style.getPropertyValue("padding-top"))
    var padding_bottom = parseInt(style.getPropertyValue("padding-bottom"))
    var border_top = parseInt(style.getPropertyValue("border-top-width"))
    var border_bottom = parseInt(style.getPropertyValue("border-bottom-width"))
    height = height - padding_top - padding_bottom - border_top - border_bottom
  }
  var lines = height / line_height
  return lines
}

完整代码

<template>
  <div ref="wrapDom" class="show-tooltip-overflow-index">
    <div ref="textDom" class="no-overflow-text" :class="lineClamp == 1 ? 'single' : 'multi'" v-if="!isOverflow">{{ text
      }}</div>
    <a-tooltip v-else>
      <template #title>{{ text }}</template>
      <span :class="lineClamp == 1 ? 'single-overflow-text' : 'multi-overflow-text'">{{ text }}</span>
    </a-tooltip>
  </div>
</template>
<script lang="ts" setup>
import { ref, onMounted } from 'vue';
const props = defineProps({
  text: {
    type: String,
    required: true
  },
  lineClamp: {
    type: Number,
    default: 1
  }
})
const textDom = ref();
const wrapDom = ref();
const isOverflow = ref(false);

onMounted(() => {
  if (props.lineClamp == 1) {
    isOverflow.value = textDom.value?.scrollWidth > wrapDom.value?.clientWidth;
  } else {
    isOverflow.value = countLines(textDom.value) > props.lineClamp;
  }
})

const countLines = (target) => {
  var style = window.getComputedStyle(target, null)
  var height = parseInt(style.getPropertyValue("height"))
  var font_size = parseInt(style.getPropertyValue("font-size"))
  var line_height = parseInt(style.getPropertyValue("line-height"))
  var box_sizing = style.getPropertyValue("box-sizing")

  if (isNaN(line_height)) line_height = font_size * 1.2

  if (box_sizing == "border-box") {
    var padding_top = parseInt(style.getPropertyValue("padding-top"))
    var padding_bottom = parseInt(style.getPropertyValue("padding-bottom"))
    var border_top = parseInt(style.getPropertyValue("border-top-width"))
    var border_bottom = parseInt(style.getPropertyValue("border-bottom-width"))
    height = height - padding_top - padding_bottom - border_top - border_bottom
  }
  var lines = height / line_height
  return lines
}

</script>
<style lang="less" scoped>
.show-tooltip-overflow-index {

  .no-overflow-text.single {
    white-space: nowrap;
  }

  .multi-overflow-text {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: v-bind('lineClamp');
    overflow: hidden;
  }

  .single-overflow-text {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    display: inline-block;
    width: 100%;
  }
}
</style>