文字过长时的优雅处理

722 阅读2分钟

前言

在业务开发中,总是会碰到一行文字过长时,超出了内容

<div style="width: 100px; border: 1px solid #ccc">This is some long text that will not fit in the box</div>

image.png

一般的处理方法是通过样式来进行控制

text-overflow:ellipsis;
white-space:nowrap; 
overflow:hidden; 

image.png

但随之而来碰到的问题是,如何显示超出部分的文字,实现也很简单,使用el-tooltip组件进行一层包装

<el-tooltip 
    class="item" 
    effect="dark" 
    content="This is some long text that will not fit in the box" placement="top-start">
  <div style="width: 100px; border: 1px solid #ccc">This is some long text that will not fit in the box</div>
</el-tooltip>

但如果每次进行如此操作显得不够优雅,于是才有了下面的思路


封装组件

在开始之前首先需要了解scrollWidth、offsetWidth、clientWidth的关系

image.png

clientWidth = padding + content
offsetWidth = padding + content + border
scrollWidth = padding + content(包含溢出部分)

正常情况下(内容不溢出并且没有border)offsetWidth === scrollWidth

所以可以通过offsetWidth < scrollWidth来进行判断

首先我们期望正常外层写法类似于

<custom-text>
    超长文字
</custom-text>

所以可以通过this.$slots.default获取这个slots,为了统一进行ref获取,我们在外层包装一层span

const content = (
    <span
        class="content"
        id="saveRef"
        ref="saveRef"
    >
        {this.$slots.default}
    </span>
);

在组件挂载的时候进行长度的判断来进行判断是否需要显示提示

data() {
    return {
        hasToolTip: false
    }
},
mounted() {
    this.updateToolTip();
},
methods: {
    updateToolTip() {
      this.hasToolTip =
        this.$refs['saveRef'].offsetWidth < this.$refs['saveRef'].scrollWidth;
    }
}

如果存在文字过长,一行超出的情况

<el-tooltip
    content={text}
    class="item"
    effect="dark"
    placement="top-start"
>
    {content}
</el-tooltip>

这里有两种选择来进行提示内容的设置

  1. 通过获取content中的innerHTML slots在vue中的表示类似于这样
const slots = {
    default: [VNode]
}

但也可能外层传过来的时候本来就包装了span,此时slots类似于这样

const slots = {
    default: [{
        ...
        children: [VNode]
    }]
}

所以我们可以这样进行获取

const text = this.$slots.default[0].text || this.$slots.default[0].children[0].text
  1. 通过外部传参进行获取
<custom-text :text="text">
    content
</custom-text>
props: {
    text: {
        type: String,
        default: ''
    }
}
const text = this.text;

PS: 为了避免不必要的计算比较,可以将计算是否需要tooltip放在鼠标移上去的时候

最终可以这样表示

render() {
    const content = (
      <span
        class="content"
        id="saveRef"
        ref="saveRef"
        onMouseover={this.updateToolTip}
      >
        {this.$slots.default}
      </span>
    );
    const text =
      this.$slots.default[0].text ||
      this.$slots.default[0].children[0].text ||
      this.text;
    return this.hasToolTip ? (
      <el-tooltip
        content={text}
        class="item"
        effect="dark"
        placement="top-start"
      >
        {content}
      </el-tooltip>
    ) : (
      content
    );
  }

总结

总的来说,还是需要掌握基础,了解了基础的一些知识才能够应对更加复杂的场景,有更多解决办法的思路。前端学习的路还很长,继续在学习优雅的路上前进。写这篇文章的初衷,一方面记忆自己的思路,另一方面分享给大家一起学习,如果写的不正确的地方,还希望得到各位大佬的指正,谢谢!

custom-text

参考

html-how-can-i-show-tooltip-only-when-ellipsis-is-activated