传统解决方案通常通过比较元素的 scrollWidth
与 clientWidth
来判断文本是否被截断。
此外,我们可以使用 Range
的方式更精确地判断文本是否被截断。
overflow: hidden
在布局上会将文本进行截断,但是双击全选复制的时候,可以复制到全部的内容。因此我们可以基于此特性,通过 浏览器提供的Range
api 获取 文本的宽度/高度进行判断。
const app = document.getElementById('app')
const range = document.createRange()
range.setStart(app, 0)
range.setEnd(app, app.childNodes.length)
const { width: rangeWidth, height: rangeHeight } =
range.getBoundingClientRect()
const { width, height } = target.getBoundingClientRect()
if (rangeWidth > width || rangeHeight > height) {
// 文本被截断 执行的逻辑
}
何时使用 Range
正常布局下,Range
都可以使用 scrollWidth
的方式平替。
当布局出现异常布局偏移时,scrollWidth
可能无法准确判断文本是否被截断。
异常布局偏移:正常文字的排列方向都是从左往右,右区域超出的部分被
hidden
截断,此时的scrollWidth
会包括hidden
的部分宽度,如果使用 css 的一些属性使得文字排列从左开始就已经被截断了一部分,最开始截断的部分是不会算在
scrollWidth
中。简单总结:如果文本排列是从左到右布局,右边被截断的部分会算在
scrollWidth
中,而左边被截断的部分不会。
举个例子:如果元素使用了 text-indent: -50px;
的方式进行了负缩进而被隐藏了。
.text-container {
width: 200px;
overflow: hidden;
border: 1px solid #000;
}
.text-container p {
display: inline-block;
text-indent: -50px; /* 负缩进 */
white-space: nowrap;
}
<div class="text-container" id="text">
<p>这是一个带有负缩进的长文本。</p>
</div>
<button onclick="checkScrollWidth()">使用 scrollWidth 检测</button>
<button onclick="checkRange()">使用 createRange 检测</button>
function checkScrollWidth() {
const textElement = document.getElementById('text');
if (textElement.scrollWidth > textElement.clientWidth) {
console.log('文本被截断了 (scrollWidth 检测)');
} else {
console.log('文本未被截断 (scrollWidth 检测)');
}
}
function checkRange() {
const textElement = document.getElementById('text');
const range = document.createRange();
range.setStart(textElement, 0)
range.setEnd(textElement, textElement.childNodes.length) // 选择 p 标签内容
const rangeWidth = range.getBoundingClientRect().width;
if (rangeWidth > textElement.clientWidth) {
console.log('文本被截断了 (createRange 检测)');
} else {
console.log('文本未被截断 (createRange 检测)');
}
}
此时两者的判断结果是有差异的,由于布局向左偏移了 50px
,没有造成滚动条,因此scrollWidth
的方式判断为文本没有截断。而range
则包含了左边截断的部分的宽度。