HTML metin taşması üç nokta algılama


176

Bir sayfada blok öğeleri koleksiyonum var. Hepsinde beyaz boşluk, taşma, metin taşması ayarlanmış CSS kuralları vardır, böylece taşan metin kesilir ve üç nokta kullanılır.

Ancak, tüm öğeler taşmaz.

Yine de hangi öğeleri taşan algılamak için javascript kullanabilirsiniz?

Teşekkürler.

Eklendi: örnek HTML yapısı ile çalışıyorum.

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

SPAN elemanları her zaman hücrelere uyar, üç nokta kuralı uygulanır. Üç nokta, SPAN'ın metin içeriğine ne zaman uygulandığını tespit etmek istiyorum.



10
Kopya değil! Bu soru, başka bir üst öğenin içindeki bir öğeyle ilgilidir. Tek bir öğedeki metin hakkında konuşuyorum. Benim durumumda, TD'deki SPAN asla TD'yi taşmaz, taşan ve kırpılan SPAN içindeki metindir. Bunu tespit etmeye çalışıyorum! Üzgünüm - bu soruyu daha iyi sorabilirdim itiraf ediyorum.
deanoj

Oh, eklemeyi unuttum - bu sadece yardımcı olursa webkit üzerinde çalışmak gerekir ...
deanoj

Ghommey'i sadece işe yarayıp yaramadığını görmek için yaptım ... olmadı.
deanoj

üç nokta yönü önemsizdir; tek yapmanız gereken taşmış olup olmadığı.
Spudley

Yanıtlar:


114

Bir zamanlar bunu yapmam gerekiyordu ve karşılaştığım tek tarayıcılar arası güvenilir çözüm hack işiydi. Böyle çözümlerin en büyük hayranı değilim, ama kesinlikle tekrar tekrar doğru sonuç veriyor.

Fikir, öğeyi klonlamanız, sınırlama genişliğini kaldırmanız ve klonlanan öğenin orijinalden daha geniş olup olmadığını test etmenizdir. Eğer öyleyse, bunun kesileceğini biliyorsunuz.

Örneğin, jQuery kullanarak:

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();

Bunu göstermek için bir jsFiddle yaptım, http://jsfiddle.net/cgzW8/2/

JQuery için kendi özel sözde seçicinizi bile oluşturabilirsiniz:

$.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;
};

Sonra öğeleri bulmak için kullanın

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

Demo: http://jsfiddle.net/cgzW8/293/

Umarım bu yardımcı olur, hacky olduğu gibi.


1
@Lauri No; CSS kesmesi kutudaki gerçek metni değiştirmez , bu nedenle içerik, kesilmiş, görünür veya gizli olsun, her zaman aynıdır. Programlı olarak kesilmiş metni almanın hiçbir yolu yoktur, eğer öyleyse ilk etapta elemanı klonlamanız gerekmez!
Christian

1
Bunun, hiç olmadığı durumlarda işe yaramayacağı anlaşılıyor white-space: nowrap.
Jakub Hampl

2
Söylemeliyim ki, internette LOT aradıktan ve birçok çözüm uygulamaya çalıştıktan sonra, bulduğum en güvenilir çözüm. Bu çözüm, element.innerWidth veya element.OffsetWidth gibi tarayıcılar arasında farklı sonuçlar vermez. Kenar boşlukları veya dolgu kullanırken sorun yaşar .. Harika bir çözüm, Aferin.
Komut Dosyası

1
Benim için bu hiçbir yerde işe yaramadı. Emin değilim, nasıl CSS bağlıdır (giriş kontrollerinde kullanmaya çalıştım, aşağıdaki çözümler en azından Chrome ve Firefox'ta çalıştı (ancak IE11'de değil))
Alexander

3
Özellikle jQuery sözde seçici kullanarak harika bir çözüm. Ancak bazen öğe çalışmayabilir, çünkü öğe metni farklı bir stile sahipse (yazı tipi boyutu, harf aralığı, iç öğelerin kenar boşlukları) genişlik yanlış hesaplanır. Bu durumda, klon elemanını 'body' yerine $ this.parent () öğesine eklemenizi tavsiye ederim. Bu elemanın tam bir kopyasını verecektir ve hesaplamalar doğru olacaktır. Neyse teşekkürler
Alex

286

Span öğesini bağımsız değişken olarak ileterek bu JS işlevini deneyin:

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

10
Bu cevap olmalı - çok zarif ve Chrome ve IE üzerinde çalışıyor (9)
Roy Truelove

14
Bu cevap ve Alex'in yanıtı IE8'de çalışmaz; kaydırma genişliğinin ve dış genişliğinin aynı olduğu bazı garip durumlar vardır ... ancak üç nokta vardır ve sonra aynı oldukları bazı durumlar vardır ... ve elips yoktur. Başka bir deyişle, ilk çözüm tüm tarayıcılarda çalışan tek çözümdür.

3
OffsetWidth, scrollWidth ve clientWidth'i anlamak isteyenler için, burada çok iyi bir açıklama var: stackoverflow.com/a/21064102/1815779
Linh Dam

4
Üzerinde text-overflow:ellipsisolmalıe.offsetWidth <= e.scrollWidth
oriadam

4
Esnek çocuklarda her zaman birbirlerine eşittirler ve bu nedenle onlar için çalışmazlar.
Kevin Beal

14

Italo'nun cevabına ek olarak, bunu jQuery kullanarak da yapabilirsiniz.

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

Ayrıca, Smoky'nin belirttiği gibi, width () yerine jQuery outerWidth () öğesini kullanmak isteyebilirsiniz.

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

9

Christian Varga'nın kabul ettiği cevabı kullanan (veya kullanmayı planlayanlar) için lütfen performans sorunlarının farkında olun.

DOM'yi bu şekilde klonlamak / değiştirmek , aşırı kaynak yoğun olan DOM Reflow'a ( DOM reflow ile ilgili bir açıklamaya bakın ) neden olur.

Christian Varga'nın çözümünü bir sayfada 100'den fazla öğe üzerinde kullanmak, JS iş parçacığının kilitlendiği 4 saniyelik bir yeniden akış gecikmesine neden oldu. JS'nin tek iş parçacıklı olduğu düşünüldüğünde, bu son kullanıcı için önemli bir UX gecikmesi anlamına gelir.

Italo Borssatto'nun cevabı kabul edilmiş olmalı, profilleme sırasında yaklaşık 10 kat daha hızlıydı.


2
Ne yazık ki her senaryoda işe yaramıyor (keşke yapsaydı). Burada bahsettiğiniz performans isabeti, yalnızca kontrol etmeniz gereken durum için çalıştırılarak dengelenebilir - sadece mouseenterbir ipucunun gösterilmesi gerekip gerekmediğini görmek için.
Jacob

5

İtalo cevap çok iyi! Ancak biraz daha hassaslaştıralım:

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

Çapraz tarayıcı uyumluluğu

Eğer, aslında, yukarıdaki kod ve kullanımını denemek console.logdeğerlerini yazdırmak e.offsetWidthve e.scrollWidthhiçbir metin kesme olmadığında bile, sen IE üzerinde, göreceksiniz, bir değer farkı 1pxveya 2pxdeneyimlidir.

Bu nedenle, kullandığınız yazı tipi boyutuna bağlı olarak, belirli bir toleransa izin verin!


IE10'da çalışmaz - offsetWidth, scrollWidth ile aynıdır ve her ikisi de kesilmiş genişliği verir.
SsjCosty

1
Bu toleransın Chrome 60'da (en son) da ihtiyacım var.
Jan Żankowski

5

elem.offsetWdith VS ele.scrollWidth Bu benim için çalışıyor! https://jsfiddle.net/gustavojuan/210to9p1/

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

Ne mevcut Chrome'da ne de Firefox'ta çalışmıyor. Her iki öğe de kırmızı olur.
xehpuk

4

Bu örnek, metin kesilmiş hücre tablosundaki araç ipucunu gösterir. Tabla genişliğine göre dinamik mi:

$.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);
    });
});

Demo: https://jsfiddle.net/t4qs3tqs/

JQuery'nin tüm sürümlerinde çalışır


1

Bence bunu tespit etmenin daha iyi bir yolu var, getClientRects()her rect aynı yüksekliğe sahip gibi görünüyor, bu yüzden farklı sayı sayısıyla satır sayısını hesaplayabiliriz top.

getClientRectsgibi işler bu

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;
}

getRowRectsgibi işler bu

Eğer gibi algılayabilir bu


1

Tüm çözümler gerçekte ne benim için işe yaramadı did iş unsurları karşılaştırmak edildi scrollWidthiçin scrollWidth(ki eleman tetiği vardır bağlı veya çocuk) üst biriminin.

Çocuğun scrollWidthebeveynlerinden daha yüksek olması .text-ellipsis, aktif olduğu anlamına gelir .


eventÜst öğe ne zaman

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

eventAlt öğe ne zaman

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

0

e.offsetWidth < e.scrollWidthÇözümü her zaman çalışmıyor.

Ve saf JavaScript kullanmak istiyorsanız, bunu kullanmanızı tavsiye ederim:

(Daktilo versiyonu)

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;
    }
}

0

@ItaloBorssatto çözümü mükemmel. Ama SO'ya bakmadan önce kararımı verdim. İşte burada :)

const elems = document.querySelectorAll('span');
elems.forEach(elem => {
  checkEllipsis(elem);
});

function checkEllipsis(elem){
  const canvas = document.createElement('canvas');
  const ctx = canvas.getContext('2d');
  const styles = getComputedStyle(elem);
  ctx.font = `${styles.fontWeight} ${styles.fontSize} ${styles.fontFamily}`;
  const widthTxt = ctx.measureText(elem.innerText).width;
  if (widthTxt > parseFloat(styles.width)){
    elem.style.color = 'red'
  }
}
span.cat {
    display: block;
    border: 1px solid black;
    white-space: nowrap;
    width: 100px;
    overflow: hidden;
    text-overflow: ellipsis;
}
 <span class="cat">Small Cat</span>
      <span class="cat">Looooooooooooooong Cat</span>


0

Uygulamam)

const items = 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}`;
  const text = ctx.measureText(el.innerText);
  return text.width > widthEl;
}
.item{
  width: 60px;
  overflow: hidden;
  text-overflow: ellipsis;
}
      <div class="item">Short</div>
      <div class="item">Loooooooooooong</div>


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.