我们经常会碰到类似这样的需求–当文字超出容器宽度,超出部分使用省略号显示,鼠标移入的时候使用tooltip提示.
超出部分使用省略号显示很简单,使用CSS即可,关键属性text-overflow: ellipsis;
.
当文字超出宽度时计算文字与容器宽度,决定是否启用TOOLTIP就稍稍麻烦一点,总结大致方案3种
- 新建一个不可见容器,在容器内填充相同文字,然后读取容器宽度. 需要注意的是,此容器要求不可见但需要渲染,否则宽度读取会不正常.场景方案为设置Z轴为负值\opicty为0\ visibility为hidden等方案
优点:兼容性好,JQ时代普遍采用的方案
此解决方案缺点:主要在于有多余的DOM节点,而我们知道DOM渲染开销是很”贵”的,大量使用时会明显影响性能.需要处理很多样式上的问题.
- 通过Range对象计算文字渲染宽度,通过getComputedStyle获得CSS属性,进而获得文字渲染需要的宽度
大致代码如下:1
2
3
4
5
6
7
8
9const 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属性读出来就变成了字符串,无法保留像子节点那样保留其样式信息)
查询一番后找到了第三种方案
- 针对
input
一类标签,使用clientWidth
与scrollWidth
对比
input
一类标签在渲染文本时,会讲超出部分渲染为横向滚动,并且scrollWidth
能读到其渲染完毕所需的正常值
核心代码就一句话:1
2
3
4
5const visible = this.$input.clientWidth < this.$input.scrollWidth
if(visible){
// TODO something
}
全文完