ChatGPT解决这个技术问题 Extra ChatGPT

HTML文本溢出省略号检测

我在页面上有一组块元素。它们都设置了 CSS 规则空白、溢出、文本溢出,以便修剪溢出的文本并使用省略号。

但是,并非所有元素都会溢出。

无论如何我可以使用javascript来检测哪些元素溢出?

谢谢。

补充:我正在使用的示例 HTML 结构。

<td><span>Normal text</span></td>
<td><span>Long text that will be trimmed text</span></td>

SPAN 元素始终适合单元格,它们应用了省略号规则。我想检测省略号何时应用于 SPAN 的文本内容。

不是重复的!这个问题是关于另一个父元素中的一个元素。我说的是单个元素中的文本。就我而言,TD 中的 SPAN 永远不会溢出 TD,而是 SPAN 中的文本溢出并被修剪。这就是我想要检测的!抱歉 - 我承认我本可以更好地提出这个问题。
哦,我忘了补充——如果有帮助的话,这只需要在 webkit 上工作......
我做了 Ghommey 只是为了看看它是否有效......它没有。
省略号方面无关紧要;您需要检测的只是它是否溢出。

I
Italo Borssatto

试试这个 JS 函数,将 span 元素作为参数传递:

function isEllipsisActive(e) {
     return (e.offsetWidth < e.scrollWidth);
}

这应该是答案 - 非常优雅,适用于 Chrome 和 IE(9)
这个答案和 Alex 的答案在 IE8 中不起作用;在某些奇怪的情况下,滚动宽度和外部宽度相同……但它有省略号,然后在某些情况下它们相同……并且没有省略号。换句话说,第一个解决方案是唯一适用于所有浏览器的解决方案。
对于需要了解offsetWidth、scrollWidth和clientWidth的人,这里有一个很好的解释:stackoverflow.com/a/21064102/1815779
text-overflow:ellipsis 上应该是 e.offsetWidth <= e.scrollWidth
他们在弹性孩子上总是相互平等的,因此对他们不起作用。
C
Christian

曾几何时,我需要这样做,而我遇到的唯一跨浏览器可靠的解决方案是 hack 工作。我不是这样的解决方案的最大粉丝,但它肯定会一次又一次地产生正确的结果。

这个想法是克隆元素,删除任何边界宽度,并测试克隆的元素是否比原始元素宽。如果是这样,您知道它将被截断。

例如,使用 jQuery:

var $element = $('#element-to-test');
var $c = $element
           .clone()
           .css({display: 'inline', width: 'auto', visibility: 'hidden'})
           .appendTo('body');

if( $c.width() > $element.width() ) {
    // text was truncated. 
    // do what you need to do
}

$c.remove();

我制作了一个 jsFiddle 来演示这一点,http://jsfiddle.net/cgzW8/2/

你甚至可以为 jQuery 创建自己的自定义伪选择器:

$.expr[':'].truncated = function(obj) {
  var $this = $(obj);
  var $c = $this
             .clone()
             .css({display: 'inline', width: 'auto', visibility: 'hidden'})
             .appendTo('body');

  var c_width = $c.width();
  $c.remove();

  if ( c_width > $this.width() )
    return true;
  else
    return false;
};

然后用它来查找元素

$truncated_elements = $('.my-selector:truncated');

演示:http://jsfiddle.net/cgzW8/293/

希望这会有所帮助,尽管它很老套。


@劳里不; CSS 截断不会更改框中的实际文本,因此内容始终相同,无论是截断、可见还是隐藏。仍然没有办法以编程方式获取截断的文本,如果有那么你就不需要首先克隆元素!
似乎这在没有 white-space: nowrap 的情况下不起作用。
我必须说,在互联网上搜索了很多并尝试实施许多解决方案之后,这是迄今为止我发现的最可靠的一个。此解决方案不会在 element.innerWidth 或 element.OffsetWidth 等浏览器之间给出不同的结果,这在使用边距或填充时会出现问题。很好的解决方案,干得好。
对我来说,这在任何地方都不起作用。我不确定它如何依赖 CSS(我尝试在输入控件上使用它,以下解决方案至少在 Chrome 和 Firefox 中有效(但在 IE11 中无效))...
很好的解决方案,尤其是使用 jQuery 伪选择器。但有时可能不起作用,因为如果元素文本具有不同的样式(字体大小、字母间距、内部元素的边距),则会错误地计算宽度。在这种情况下,我建议将克隆元素附加到 $this.parent() 而不是“body”。这将提供元素的精确副本,并且计算将是正确的。不管怎么说,还是要谢谢你
A
Alex K

添加到 italo 的答案,您也可以使用 jQuery 来执行此操作。

function isEllipsisActive($jQueryObject) {
    return ($jQueryObject.width() < $jQueryObject[0].scrollWidth);
}

此外,正如 Smoky 所指出的,您可能希望使用 jQuery outerWidth() 而不是 width()。

function isEllipsisActive($jQueryObject) {
    return ($jQueryObject.outerWidth() < $jQueryObject[0].scrollWidth);
}

R
RyanGled

对于那些使用(或计划使用)Christian Varga 接受的答案的人,请注意性能问题。

以这种方式克隆/操作 DOM 会导致 DOM 回流(请参阅此处的 an explanation on DOM reflow),这会占用大量资源。

对页面上的 100 多个元素使用 Christian Varga 的解决方案会导致 4 秒的回流延迟,在此期间 JS 线程被锁定。考虑到 JS 是单线程的,这对最终用户来说意味着很大的 UX 延迟。

Italo Borssatto 的 answer 应该是被接受的,在我的分析过程中它快了大约 10 倍。


不幸的是,它并非在所有情况下都有效(我希望如此)。并且您在此处提到的性能损失可以通过仅在您需要检查的情况下运行它来抵消 - 仅在 mouseenter 上查看是否需要显示工具提示。
A
Andry

italo的回答非常好!但是让我稍微改进一下:

function isEllipsisActive(e) {
   var tolerance = 2; // In px. Depends on the font you are using
   return e.offsetWidth + tolerance < e.scrollWidth;
}

跨浏览器兼容性

事实上,如果您尝试上面的代码并使用 console.log 打印出 e.offsetWidthe.scrollWidth 的值,您会注意到,在 IE 上,即使您没有文本截断,值差异也为1px2px 是有经验的。

因此,根据您使用的字体大小,允许一定的公差!


它在 IE10 上不起作用 - offsetWidth 与 scrollWidth 相同,都给了我截断的宽度。
我也需要 Chrome 60(最新)的这种容忍度。
M
Matthew Herbst

elem.offsetWdith VS ele.scrollWidth 这对我有用! https://jsfiddle.net/gustavojuan/210to9p1/

$(function() {
  $('.endtext').each(function(index, elem) {
    debugger;
    if(elem.offsetWidth !== elem.scrollWidth){
      $(this).css({color: '#FF0000'})
    }
  });
});

既不适用于当前的 Chrome 也不适用于 Firefox。两个元素都变为红色。
R
Red

此示例在单元格表上显示工具提示,其中文本被截断。基于表格宽度是动态的:

$.expr[':'].truncated = function (obj) {
    var element = $(obj);

    return (element[0].scrollHeight > (element.innerHeight() + 1)) || (element[0].scrollWidth > (element.innerWidth() + 1));
};

$(document).ready(function () {
    $("td").mouseenter(function () {
        var cella = $(this);
        var isTruncated = cella.filter(":truncated").length > 0;
        if (isTruncated) 
            cella.attr("title", cella.text());
        else 
            cella.attr("title", null);
    });
});

演示:https://jsfiddle.net/t4qs3tqs/

它适用于所有版本的 jQuery


R
Ruben Helsloot

所有的解决方案都没有真正为我工作,确实 工作是将元素 scrollWidth 与其父元素(或子元素,取决于哪个元素具有触发器)的 scrollWidth 进行比较。

当孩子的 scrollWidth 高于其父母时,这意味着 .text-ellipsis 处于活动状态。

el 是父元素时

function isEllipsisActive(el) {
    let width       = el.offsetWidth;
    let widthChild  = el.firstChild.offsetWidth;
    return (widthChild >= width);
}

el 是子元素时

function isEllipsisActive(event) {
    let width       = el.offsetWidth;
    let widthParent = el.parentElement.scrollWidth;
    return (width >= widthParent);
}

Д
Дмытрык

我的实现)

常量项 = Array.from(document.querySelectorAll('.item')); items.forEach(item =>{ item.style.color = checkEllipsis(item) ? 'red': 'black' }) function checkEllipsis(el){ const styles = getComputedStyle(el); const widthEl = parseFloat(styles.width); const ctx = document.createElement('canvas').getContext('2d'); ctx.font = `${styles.fontSize} ${styles.fontFamily}`;常量文本 = ctx.measureText(el.innerText);返回 text.width > widthEl; } .item{ 宽度:60px;溢出:隐藏;文本溢出:省略号; }

Loooooooooooong


D
Defims

我认为检测它的更好方法是使用 getClientRects(),似乎每个矩形都有相同的高度,所以我们可以用不同的 top 值的数量来计算行数。

getClientRectsthis 一样工作

function getRowRects(element) {
    var rects = [],
        clientRects = element.getClientRects(),
        len = clientRects.length,
        clientRect, top, rectsLen, rect, i;

    for(i=0; i<len; i++) {
        has = false;
        rectsLen = rects.length;
        clientRect = clientRects[i];
        top = clientRect.top;
        while(rectsLen--) {
            rect = rects[rectsLen];
            if (rect.top == top) {
                has = true;
                break;
            }
        }
        if(has) {
            rect.right = rect.right > clientRect.right ? rect.right : clientRect.right;
            rect.width = rect.right - rect.left;
        }
        else {
            rects.push({
                top: clientRect.top,
                right: clientRect.right,
                bottom: clientRect.bottom,
                left: clientRect.left,
                width: clientRect.width,
                height: clientRect.height
            });
        }
    }
    return rects;
}

getRowRectsthis 一样工作

您可以检测到 this


N
Nursultan Imanov

没有一个解决方案对我有用,所以我选择了一种完全不同的方法。我没有使用带有省略号的 CSS 解决方案,而是从特定的字符串长度中剪切文本。

  if (!this.isFullTextShown && this.text.length > 350) {
    return this.text.substring(0, 350) + '...'
  }
  return this.text

如果超出长度,则显示“更多/更少”按钮。

  <span
    v-if="text.length > 350"
    @click="isFullTextShown = !isFullTextShown"
  >
    {{ isFullTextShown ? 'show less' : 'show more' }}
  </span>

喜欢 10 年后的事实,这个问题仍然有效 - 尽管我怀疑 10 年后浏览器标准有所改善! :-)
D
David Guyon

e.offsetWidth < e.scrollWidth 解决方案并不总是有效。

如果你想使用纯 JavaScript,我建议使用这个:

(打字稿)

public isEllipsisActive(element: HTMLElement): boolean {
    element.style.overflow = 'initial';
    const noEllipsisWidth = element.offsetWidth;
    element.style.overflow = 'hidden';
    const ellipsisWidth = element.offsetWidth;

    if (ellipsisWidth < noEllipsisWidth) {
      return true;
    } else {
      return false;
    }
}

需要对每个元素进行重排可能效率很低,就像您在表格中的数百个单元格中使用它一样。
S
SONGJP

https://stackoverflow.com/users/241142/iconoclast 提到的演示 http://jsfiddle.net/brandonzylstra/hjk9mvcy/ 中有一些错误任务。

在他的演示中,添加这些代码将起作用:

setTimeout(() => {      
  console.log(EntryElm[0].offsetWidth)
}, 0)

A
Alex Cory

如果您正在做出反应,这就是我的做法。

<div 
  ref={ref => {
    if (!ref) return
    const isOverflowing = ref.scrollWidth > ref.clientWidth
    if (isOverflowing) {
      // handle what to do next here
    }
  }}
/>

M
Mike

添加到@Дмытрык 答案,缺少边框和填充的扣除才能完全发挥作用!

常量项 = Array.from(document.querySelectorAll('.item')); items.forEach(item =>{ item.style.color = checkEllipsis(item) ? 'red': 'black' }) function checkEllipsis(el){ const styles = getComputedStyle(el); const widthEl = parseFloat(styles.width); const ctx = document.createElement('canvas').getContext('2d'); ctx.font = `${styles.fontSize} ${styles.fontFamily}`;常量文本 = ctx.measureText(el.innerText);让额外= 0;额外 += parseFloat(styles.getPropertyValue('border-left-width'));额外 += parseFloat(styles.getPropertyValue('border-right-width'));额外 += parseFloat(styles.getPropertyValue('padding-left'));额外 += parseFloat(styles.getPropertyValue('padding-right'));返回 text.width > (widthEl - 额外); } .item{ 宽度:60px;溢出:隐藏;文本溢出:省略号; }

Loooooooooooong


G
Giang Le

对于使用 e.offsetWidth < e.scrollWidth 并遇到可以显示全文但仍然有省略号的错误的人。

这是因为 offsetWidthscrollWidth 总是对值进行四舍五入。例如:offsetWidth 返回 161 但实际宽度为 161.25。解决方案是使用 getBoundingClientRect

const clonedEl = e.cloneNode(true)
clonedElement.style.overflow = "visible"
clonedElement.style.visibility = "hidden"
clonedElement.style.width = "fit-content"

e.parentElement.appendChild(clonedEl)
const fullWidth = clonedElement.getBoundingClientRect().width
const currentWidth = e.getBoundingClientRect().width

return currentWidth < fullWidth


Д
Дмытрык

@ItaloBorssatto 的解决方案非常完美。但在看之前 - 我做出了决定。这里是 :)

const elems = document.querySelectorAll('span'); elems.forEach(elem => { checkEllipsis(elem); });函数 checkEllipsis(elem){ const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d');常量样式 = getComputedStyle(elem); ctx.font = `${styles.fontWeight} ${styles.fontSize} ${styles.fontFamily}`;常量 widthTxt = ctx.measureText(elem.innerText).width; if (widthTxt > parseFloat(styles.width)){ elem.style.color = 'red' } } span.cat { display: block;边框:1px纯黑色;空白:nowrap;宽度:100px;溢出:隐藏;文本溢出:省略号; } 小猫 Looooooooooooooong Cat