การตรวจจับจุดไข่ปลา HTML ข้อความ


176

ฉันมีชุดขององค์ประกอบบล็อกในหน้า พวกเขาทั้งหมดมี CSS CSS white-space, overflow, text-overflow set เพื่อให้ข้อความ overflowing ถูกตัดแต่งและใช้จุดไข่ปลา

อย่างไรก็ตามไม่ใช่องค์ประกอบทั้งหมดที่ล้น

มีอยู่แล้วฉันสามารถใช้จาวาสคริปต์เพื่อตรวจสอบองค์ประกอบที่ล้น?

ขอบคุณ

เพิ่มแล้ว: ตัวอย่างโครงสร้าง HTML ที่ฉันทำงานด้วย

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

องค์ประกอบ SPAN จะพอดีกับเซลล์เสมอโดยจะมีการใช้กฎวงรี ฉันต้องการตรวจสอบเมื่อจุดไข่ปลาถูกนำไปใช้กับเนื้อหาข้อความของ SPAN



10
ไม่ซ้ำ! คำถามนั้นเกี่ยวกับองค์ประกอบหนึ่งภายในอีกองค์ประกอบหลัก ฉันกำลังพูดถึงข้อความภายในองค์ประกอบเดียว ในกรณีของฉัน SPAN ใน TD จะไม่ล้น TD มันเป็นข้อความภายใน SPAN ที่ล้นและถูกตัดออก นั่นคือสิ่งที่ฉันพยายามตรวจจับ! ขออภัยฉันตอบคำถามนี้ได้ดีกว่าฉันยอมรับ
deanoj

โอ้ฉันลืมที่จะเพิ่ม - นี้ต้องการเพียงที่จะทำงานใน WebKit ว่าจะช่วย ...
deanoj

ฉันทำ Ghommey เพื่อดูว่ามันใช้งานได้หรือไม่
deanoj

ลักษณะของจุดไข่ปลานั้นไม่เกี่ยวข้อง สิ่งที่คุณต้องตรวจสอบก็คือมันล้น
Spudley

คำตอบ:


114

กาลครั้งหนึ่งฉันต้องทำสิ่งนี้และทางออกที่เชื่อถือได้ข้ามเบราว์เซอร์เดียวที่ฉันเจอคืองานแฮ็ค ฉันไม่ใช่แฟนตัวยงของการแก้ปัญหาแบบนี้ แต่มันให้ผลลัพธ์ที่ถูกต้องครั้งแล้วครั้งเล่า

แนวคิดคือคุณโคลนองค์ประกอบลบความกว้างของขอบเขตและทดสอบว่าองค์ประกอบที่โคลนนั้นกว้างกว่าต้นฉบับหรือไม่ ถ้าเป็นเช่นนั้นคุณรู้ว่ามันจะถูกตัดทอน

ตัวอย่างเช่นการใช้ 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/

คุณสามารถสร้าง pseudo-selector ที่คุณกำหนดเองสำหรับ 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/

หวังว่านี่จะช่วยได้แฮ็คอย่างที่มันเป็น


1
@Lauri ไม่; การตัด CSS ไม่ได้เปลี่ยนข้อความจริงในกล่องดังนั้นเนื้อหาจะเหมือนเดิมเสมอไม่ว่าจะถูกตัดทอนให้ปรากฏหรือซ่อนอยู่ ยังไม่มีวิธีที่จะได้รับข้อความที่ถูกตัดโดยทางโปรแกรมหากมีแล้วคุณไม่จำเป็นต้องโคลนองค์ประกอบในตอนแรก!
คริสเตียน

1
white-space: nowrapดูเหมือนว่านี้จะไม่ทำงานในสถานการณ์ที่ไม่มี
Jakub Hampl

2
ฉันต้องบอกว่าหลังจากค้นหามากบนอินเทอร์เน็ตและพยายามที่จะใช้วิธีแก้ปัญหาต่าง ๆ นี่เป็นสิ่งที่น่าเชื่อถือที่สุดที่ฉันค้นพบ การแก้ปัญหานี้ไม่ได้ให้ผลลัพธ์ที่แตกต่างกันระหว่างเบราว์เซอร์เช่น element.innerWidth หรือ element.OffsetWidth ซึ่งมีปัญหาเมื่อใช้ระยะขอบหรือช่องว่างภายใน .. วิธีแก้ปัญหาที่ดีทำได้ดีมาก
Scription

1
สำหรับฉันมันไม่ทำงานที่ใดก็ได้ ฉันไม่แน่ใจว่ามันขึ้นอยู่กับ CSS (ฉันได้ลองใช้มันในการควบคุมอินพุตโซลูชั่นด้านล่างทำงานได้อย่างน้อยใน Chrome และ Firefox (แต่ไม่ใช่ใน IE11)) ...
Alexander

3
สุดยอดวิธีแก้ปัญหาโดยเฉพาะการใช้ jQuery pseudo-selector แต่บางครั้งอาจไม่ทำงานเนื่องจากความกว้างถูกคำนวณอย่างไม่ถูกต้องหากข้อความองค์ประกอบมีสไตล์ที่แตกต่างกัน (ขนาดตัวอักษรระยะห่างระหว่างตัวอักษรระยะขอบขององค์ประกอบภายใน) ในกรณีนั้นฉันอยากจะแนะนำให้ผนวกองค์ประกอบของโคลนกับ $ this.parent () แทน 'body' สิ่งนี้จะให้สำเนาที่ถูกต้องขององค์ประกอบและการคำนวณจะถูกต้อง ขอบคุณอยู่แล้ว
อเล็กซ์

286

ลองใช้ฟังก์ชั่น JS นี้โดยผ่านส่วนขยายเป็นอาร์กิวเมนต์:

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

10
นี่ควรเป็นคำตอบ - สง่างามมากและใช้งานได้บน Chrome และ IE (9)
Roy Truelove

14
คำตอบนี้และคำตอบของ Alex จะไม่ทำงานใน IE8; มีบางกรณีที่ความกว้างและความกว้างของสกรอลล์ด้านนอกเท่ากัน ... แต่มันมีจุดไข่ปลาแล้วบางกรณีที่มันเหมือนกัน ... และไม่มีจุดไข่ปลา กล่าวอีกนัยหนึ่งทางออกแรกคือทางออกเดียวที่ใช้ได้กับเบราว์เซอร์ทั้งหมด

3
สำหรับผู้ที่ต้องการเข้าใจ offsetWidth, scrollWidth และ clientWidth นี่คือคำอธิบายที่ดีมาก: stackoverflow.com/a/21064102/1815779
Linh Dam

4
เมื่อวันที่text-overflow:ellipsisมันควรจะเป็นe.offsetWidth <= e.scrollWidth
oriadam

4
พวกมันจะมีค่าเท่ากันเสมอสำหรับเด็กที่ดิ้นงอและดังนั้นจะไม่ได้ผลสำหรับพวกเขา
Kevin Beal

14

เมื่อเพิ่มคำตอบของ italo คุณสามารถทำได้โดยใช้ jQuery

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

นอกจากนี้เมื่อ Smoky ชี้ให้เห็นคุณอาจต้องการใช้ jQuery outerWidth () แทน width ()

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

9

สำหรับผู้ที่ใช้ (หรือวางแผนที่จะใช้) คำตอบที่ยอมรับจาก Christian Varga โปรดระวังปัญหาด้านประสิทธิภาพ

การโคลน / จัดการ DOM ในลักษณะที่ทำให้DOM Reflow (ดูคำอธิบายเกี่ยวกับ DOM reflowที่นี่) ซึ่งมีทรัพยากรอย่างมาก

การใช้วิธีการแก้ปัญหาของ Christian Varga บนองค์ประกอบกว่า 100+ บนหน้าเว็บทำให้เกิดการหน่วงเวลาการ reflow 4 วินาทีระหว่างที่ล็อคเธรด JS การพิจารณา JS เป็นเธรดเดี่ยวซึ่งหมายถึงการหน่วงเวลา UX อย่างมีนัยสำคัญต่อผู้ใช้ปลายทาง

คำตอบของ Italo Borssatto ควรเป็นคำตอบที่ยอมรับได้เร็วกว่าประมาณ 10 เท่าในระหว่างการทำโปรไฟล์ของฉัน


2
น่าเสียดายที่มันไม่ทำงานในทุกสถานการณ์ (ฉันหวังว่ามันจะ) และประสิทธิภาพที่คุณพูดถึงในที่นี้สามารถชดเชยได้ด้วยการดำเนินการตามสถานการณ์ที่คุณจำเป็นต้องตรวจสอบเท่านั้นmouseenterเพื่อดูว่าจะต้องแสดงคำแนะนำเครื่องมือหรือไม่
Jacob

5

คำตอบจากอิตาโลดีมาก! อย่างไรก็ตามให้ฉันปรับแต่งเล็กน้อย:

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

ความเข้ากันได้ข้ามเบราว์เซอร์

หากในความเป็นจริงคุณลองใช้รหัสด้านบนและใช้console.logเพื่อพิมพ์ค่าของe.offsetWidthและe.scrollWidthคุณจะสังเกตเห็นบน IE ว่าแม้ว่าคุณจะไม่มีการตัดทอนข้อความความแตกต่างของค่า1pxหรือ2pxมีประสบการณ์

ดังนั้นขึ้นอยู่กับขนาดตัวอักษรที่คุณใช้


มันไม่ทำงานบน IE10 - offsetWidth เหมือนกับ scrollWidth ทั้งสองให้ความกว้างที่ถูกตัดทอน
SsjCosty

1
ฉันต้องการความอดทนใน Chrome 60 (ล่าสุด) ด้วย
ม.ค. Żankowski

5

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 ปัจจุบัน องค์ประกอบทั้งสองกลายเป็นสีแดง
xehpuk

4

ตัวอย่างนี้แสดงคำแนะนำเครื่องมือบนตารางเซลล์ที่มีข้อความถูกตัดทอน เป็นแบบไดนามิกตามความกว้างของตาราง:

$.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 ทุกรุ่น


1

ฉันคิดว่าวิธีที่ดีกว่าในการตรวจสอบคือการใช้getClientRects()ดูเหมือนว่าแต่ละ rect มีความสูงเท่ากันดังนั้นเราจึงสามารถคำนวณจำนวนบรรทัดด้วยจำนวนtopค่าที่แตกต่างกัน

getClientRectsทำงานเช่นนี้

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

getRowRectsทำงานเช่นนี้

คุณสามารถตรวจจับเช่นนี้


1

การแก้ปัญหาทั้งหมดไม่ได้ผลสำหรับฉันสิ่งที่ได้ผลคือการเปรียบเทียบองค์ประกอบscrollWidthกับscrollWidthของผู้ปกครอง (หรือเด็กขึ้นอยู่กับองค์ประกอบที่มีทริกเกอร์)

เมื่อเด็กscrollWidthสูงกว่าพ่อแม่ก็จะแสดงว่า.text-ellipsisมีความกระตือรือร้น


เมื่อeventใดคือองค์ประกอบหลัก

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

eventองค์ประกอบของเด็กคือเมื่อใด

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

0

e.offsetWidth < e.scrollWidthแก้ปัญหาคือไม่ทำงานเสมอ

และถ้าคุณต้องการใช้จาวาสคริปต์ที่บริสุทธิ์ฉันขอแนะนำให้ใช้สิ่งนี้:

(typescript)

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 นั้นสมบูรณ์แบบ แต่ก่อนที่จะดู SO - ฉันตัดสินใจ นี่คือ :)

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

การใช้งานของฉัน)

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>


0

มี mistasks บางส่วนในการสาธิตhttp://jsfiddle.net/brandonzylstra/hjk9mvcy/กล่าวโดยhttps://stackoverflow.com/users/241142/iconoclast

ในการสาธิตของเขาเพิ่มรหัสเหล่านี้จะทำงาน:

setTimeout(() => {      
  console.log(EntryElm[0].offsetWidth)
}, 0)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.