计算文字宽度

我们经常会碰到类似这样的需求–当文字超出容器宽度,超出部分使用省略号显示,鼠标移入的时候使用tooltip提示.
超出部分使用省略号显示很简单,使用CSS即可,关键属性text-overflow: ellipsis;.

当文字超出宽度时计算文字与容器宽度,决定是否启用TOOLTIP就稍稍麻烦一点,总结大致方案3种

  1. 新建一个不可见容器,在容器内填充相同文字,然后读取容器宽度. 需要注意的是,此容器要求不可见但需要渲染,否则宽度读取会不正常.场景方案为设置Z轴为负值\opicty为0\ visibility为hidden等方案

优点:兼容性好,JQ时代普遍采用的方案
此解决方案缺点:主要在于有多余的DOM节点,而我们知道DOM渲染开销是很”贵”的,大量使用时会明显影响性能.需要处理很多样式上的问题.

  1. 通过Range对象计算文字渲染宽度,通过getComputedStyle获得CSS属性,进而获得文字渲染需要的宽度
    大致代码如下:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    const range = document.createRange();
    range.setStart(targetElement, 0);
    range.setEnd(targetElement, targetElement.childNodes.length);
    const rangeWidth = range.getBoundingClientRect().width;
    const padding = getComputedStyle(elem,null).getPropertyValue("paddingLeft") + getComputedStyle(elem,null).getPropertyValue("paddingRight")

    const renderWidth = rangeWidth + padding

    // TODO something

优点: Range对象比渲染DOM开销更小,性能更好. 社区很多基础库均使用此方案(比如element判断单元格是否超出提示)
缺点: 兼容性差一点

到此为止,本以为就差不多了,结果项目来了一个使用场景:
业务里很多表单填报,input框可输入诸如公司名称、部门名称等长度变化特变广的输入框,也需要使用如上功能(超出宽度时显示省略号,鼠标移入则弹出TOOLTIP提示),初版直接使用title属性,但显示逻辑与样式均无法达到满意.使用上述方案2发现难以设置range对象(input的value属性读出来就变成了字符串,无法保留像子节点那样保留其样式信息)

查询一番后找到了第三种方案

  1. 针对input一类标签,使用clientWidthscrollWidth对比

input一类标签在渲染文本时,会讲超出部分渲染为横向滚动,并且scrollWidth能读到其渲染完毕所需的正常值

核心代码就一句话:

1
2
3
4
5
const visible = this.$input.clientWidth < this.$input.scrollWidth

if(visible){
// TODO something
}

全文完

坚持原创技术分享,您的支持将鼓励我继续创作!
0%