Tràn văn bản nhiều dòng trên trình duyệt với dấu chấm lửng được nối trong một chiều rộng và chiều cao cố định


178

Tôi đã tạo một hình ảnh cho câu hỏi này để dễ hiểu hơn.

Có thể tạo một dấu chấm lửng trên a <div>với chiều rộng cố định và nhiều dòng không?

tràn văn bản

Tôi đã thử một số plugin jQuery ở đây và ở đó, nhưng không thể tìm thấy plugin tôi đang tìm kiếm. Có khuyến nghị nào không? Ý tưởng?



1
stackoverflow.com/questions/3922739/ cho giải pháp chỉ dành cho css
Evgeny


2
Đối với bất cứ ai tìm kiếm điều này vào giữa năm 2016, câu trả lời ngắn gọn là: KHÔNG, điều đó là không thể trong trình duyệt chéo, thanh lịch, CSS. Giải pháp thường được đưa ra là gần nhất để hoàn thành ( codepen.io/romanrudenko/pen/ymHFh ) là Goldbergian nó làm cho tất cả cơ thể bạn bị tổn thương, và vẫn còn khá xấu xí.
konrad

Câu trả lời:


91

Chỉ là một ý tưởng cơ bản nhanh chóng.

Tôi đã thử nghiệm với đánh dấu sau:

<div id="fos">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin nisi ligula, dapibus a volutpat sit amet, mattis et dui. Nunc porttitor accumsan orci id luctus. Phasellus ipsum metus, tincidunt non rhoncus id, dictum a lectus. Nam sed ipsum a lacus sodales eleifend. Vestibulum lorem felis, rhoncus elementum vestibulum eget, dictum ut velit. Nullam venenatis, elit in suscipit imperdiet, orci purus posuere mauris, quis adipiscing ipsum urna ac quam.</p>  
</div>

Và CSS:

#fos { width: 300px; height: 190px; overflow: hidden; }
#fos p { padding: 10px; margin: 0; }

Áp dụng jQuery này sẽ đạt được kết quả mong muốn:

var $p = $('#fos p');
var divh = $('#fos').height();
while ($p.outerHeight() > divh) {
    $p.text(function (index, text) {
        return text.replace(/\W*\s(\S)*$/, '...');
    });
}

Nó liên tục cố gắng loại bỏ từ cuối cùng của văn bản cho đến khi đạt đến kích thước mong muốn. Vì tràn: ẩn; quá trình này vẫn vô hình và ngay cả khi tắt JS, kết quả vẫn là "chính xác trực quan" (tất nhiên không có "...").

Nếu bạn kết hợp điều này với một cắt ngắn hợp lý ở phía máy chủ (chỉ để lại một chi phí nhỏ) thì nó sẽ chạy nhanh hơn :).

Một lần nữa, đây không phải là một giải pháp hoàn chỉnh, chỉ là một ý tưởng.

CẬP NHẬT: Đã thêm bản demo jsFiddle .


1
giải pháp tuyệt vời @bazmegakapa ... nhưng tôi có một số vấn đề khi cố gắng thích ứng với trường hợp của mình. Tôi có nhiều thứ khác nhau livà bên trong mỗi cái có .blockmột .block h2và tôi cần áp dụng cái này vào h2bên trong .blocknhưng tôi không thể làm cho nó hoạt động được. Có bất kỳ khác nhau nếu có nhiều hơn một .block h2?
Alex

1
Trong trường hợp của tôi, nó chỉ để lại 2 dòng văn bản khi đáng lẽ phải có 3. Rõ ràng thùng chứa của tôi nhỏ hơn dòng height*3một vài pixel. Cách khắc phục dễ dàng là chỉ cần thêm một vài pixel vàodivh
Lukas LT

3
Tôi đã có một trải nghiệm tồi tệ về vòng lặp vô hạn với tập lệnh này bởi vì văn bản chỉ chứa một từ rất dài, do đó, regrec thay thế không bao giờ khớp. Để tránh điều này, hãy thêm mã này ngay sau whiledòng:if(!$p.text().match(/\W*\s(\S)*$/)) break;
KrisWebDev

1
Mặc dù không có khả năng là một vấn đề trong trường hợp này, nhưng việc cập nhật DOM và kiểm tra bố cục liên tục là một ý tưởng tồi vì nó có thể gây ra sự chậm lại. Để giảm thiểu điều này, bạn có thể một cái gì đó tương tự như tìm kiếm nhị phân: kiểm tra xem khối văn bản đã phù hợp chưa, nếu không thì chia văn bản thành các từ hoặc ký tự và xác định giới hạn của bạn (dưới = 1 từ / ký tự, trên = tất cả các từ / ký tự) , while ((upper-lower)>1) {let middle=((lower+upper)/2)|0 /*|0 is quick floor*/; if (test(words.slice(0,middle)+'...')) {lower=middle;} else {upper=middle;}}. Như @KrisWebDev đã tìm thấy, bạn cũng sẽ muốn kiểm tra một từ khổng lồ.
Chinoto Vokro

1
Giải pháp này là tuyệt vời. Trong trường hợp của tôi, tôi cần theo dõi văn bản gốc để tôi có thể cắt ngắn toàn bộ giá trị văn bản một cách đáp ứng. Vì vậy, khi trang tải, tôi lưu trữ văn bản gốc trong một biến và trước khi tôi chạy logic này, tôi đảm bảo 'làm mới' phần tử với giá trị văn bản gốc. Thêm gỡ lỗi, và nó hoạt động tuyệt vời.
bessdrest

68

Hãy thử plugin jQuery.dotdotdot .

$(".ellipsis").dotdotdot();

11
Làm thế nào bạn sẽ phát âm đó? chấm-chấm-chấm-chấm?
JackAce

58
Thực sự rất tệ khi sử dụng> 600 dòng js để giải quyết vấn đề cần được giải quyết bằng css
Jethro Larson

Tôi đã thử nó, và nó đang hoạt động tốt. Câu trả lời nên được chấp nhận
AbdelHady

1
Hoạt động nhưng đảm bảo sử dụng sự kiện window.loaded chứ không phải $ (tài liệu). Đã (), vì phông chữ và các tài nguyên bên ngoài khác có thể ảnh hưởng đến bố cục HTML của bạn. Nếu dotdotdot thực thi trước khi tài nguyên này được tải, văn bản sẽ không bị cắt ở vị trí chính xác.
sboisse

10
Đây là một công cụ thương mại, nó có giá 5 đô la cho một trang web và 35 đô la cho nhiều trang web. Cấp phép sẽ là một nỗi đau. Tôi nghĩ rằng nó là miễn phí và ngay lập tức có thể tích hợp, không phải vậy!
gen b.

29

Thư viện Javascript cho "kẹp dòng"

Lưu ý rằng "kẹp đường" cũng được gọi là "Dấu chấm lửng trên khối nhiều đường" hoặc "dấu chấm lửng dọc".


github.com/BeSite/jQuery.dotdotdot


github.com/josephschmitt/Clamp.js


Dưới đây là một vài điều nữa tôi chưa điều tra:


Giải pháp CSS cho kẹp đường

Có một số giải pháp CSS, nhưng cách sử dụng đơn giản nhất -webkit-line-clampcó hỗ trợ trình duyệt kém . Xem bản demo trực tiếp trên jsfiddle.net/AdrienBe/jthu55v7/

Nhiều người đã nỗ lực rất nhiều để thực hiện điều này chỉ bằng CSS. Xem các bài viết và câu hỏi về nó:


Những gì tôi muốn giới thiệu

Giữ cho nó đơn giản. Trừ khi bạn có nhiều thời gian để dành cho tính năng này, hãy tìm giải pháp đơn giản và được thử nghiệm: CSS đơn giản hoặc thư viện javascript được thử nghiệm tốt.

Đi cho một cái gì đó ưa thích / phức tạp / tùy biến cao và bạn sẽ trả giá cho việc này xuống đường.


Những gì người khác làm

Có một sự mờ dần như Airbnb có thể là một giải pháp tốt. Nó có thể là CSS cơ bản kết hợp với jQuery cơ bản. Trên thực tế, nó có vẻ rất giống với giải pháp này trên CSSTricks

Giải pháp "đọc thêm" của AirBnb

Oh, và nếu bạn tìm cảm hứng thiết kế:


6

Không có tính năng như vậy trong HTML và điều này rất bực bội.

Tôi đã phát triển một thư viện để đối phó với điều này.

  • Tràn văn bản nhiều dòng: dấu chấm lửng
  • Văn bản nhiều dòng với các công nghệ không hỗ trợ nó: SVG, Canvas chẳng hạn
  • Có chính xác các ngắt dòng giống nhau trong văn bản SVG của bạn, trong kết xuất HTML và trong bản xuất PDF của bạn chẳng hạn

Kiểm tra trang web của tôi để xem ảnh chụp màn hình, hướng dẫn và liên kết tải xuống.


"Lỗi khi thiết lập kết nối db" ... bạn có thể muốn làm như mọi người khác và lưu trữ dự án của bạn trên Github, nó có thể sẽ tốt hơn cho bạn & cho cộng đồng :)
Adrien trở thành

@AdrienBe nó trên Github: github.com/rossille/jstext , và bạn nói đúng, github ổn định hơn trang web của tôi, tôi đặt trang github làm liên kết chính
Samuel Rossille

@SamuelRossille tin tuyệt vời, cảm ơn vì đã cập nhật nhanh chóng!
Adrien Be

4

Giải pháp JS thuần túy dựa trên giải pháp của bažmegakapa và một số dọn dẹp để giải thích cho những người cố gắng đưa ra chiều cao / chiều cao tối đa thấp hơn dòng của phần tử:

  var truncationEl = document.getElementById('truncation-test');
  function calculateTruncation(el) {
    var text;
    while(el.clientHeight < el.scrollHeight) {
      text = el.innerHTML.trim();
      if(text.split(' ').length <= 1) {
        break;
      }
      el.innerHTML = text.replace(/\W*\s(\S)*$/, '...');
    }
  }

  calculateTruncation(truncationEl);

Đây là mã rất không hiệu quả. Bằng cách sử dụng giao diện "while" là lỗi tiềm ẩn với vòng lặp vô hạn.
WebBrother

4

Tôi có một giải pháp hoạt động tốt nhưng thay vì dấu chấm lửng, nó sử dụng một gradient. Ưu điểm là bạn không phải thực hiện bất kỳ tính toán JavaScript nào và nó hoạt động cho các thùng chứa có chiều rộng thay đổi bao gồm các ô của bảng. Nó sử dụng một vài div phụ, nhưng nó rất dễ thực hiện.

http://salzerdesign.com/blog/?p=453

Chỉnh sửa: Xin lỗi, tôi không biết rằng liên kết là không đủ. Giải pháp là đặt một div xung quanh văn bản và tạo kiểu cho div để kiểm soát tràn. Bên trong div đặt một div khác với gradient "fade" có thể được tạo bằng CSS hoặc hình ảnh (đối với IE cũ). Độ dốc chuyển từ màu trong suốt sang màu nền của ô bảng và rộng hơn một chút so với dấu chấm lửng. Nếu văn bản dài và tràn ra, nó sẽ nằm dưới div "fade" và trông "mờ dần". Nếu văn bản ngắn, mờ dần là vô hình nên không có vấn đề. Hai thùng chứa có thể được điều chỉnh để cho phép một hoặc nhiều dòng hiển thị bằng cách đặt chiều cao của vùng chứa là bội số của chiều cao dòng văn bản. Div "fade" có thể được định vị để chỉ bao gồm dòng cuối cùng.


Vui lòng chia sẻ các phần quan trọng trong giải pháp của bạn, trên các câu trả lời chỉ liên kết SO không được phép.
kapa

khía cạnh tuyệt vời của điều này là bản thân văn bản không bị cắt ngắn, vì vậy nếu người dùng sao chép-dán bảng thì toàn bộ nội dung sẽ xuất hiện.
nguyên mẫu

Một khái niệm rất hay. Nó cũng được đề cập trong bài viết này (cách "mờ dần") Tôi tin rằng css-tricks.com/line-clampin
Adrien Be

4

Đây là một cách CSS thuần túy để thực hiện điều này: http://www.mobify.com/blog/multiline-ellipsis-in-pure-css/

Đây là một bản tóm tắt:

nhập mô tả hình ảnh ở đây

<html>
<head>
<style>
    html, body, p { margin: 0; padding: 0; font-family: sans-serif;}

    .ellipsis {
        overflow: hidden;
        height: 200px;
        line-height: 25px;
        margin: 20px;
        border: 5px solid #AAA; }

    .ellipsis:before {
        content:"";
        float: left;
        width: 5px; height: 200px; }

    .ellipsis > *:first-child {
        float: right;
        width: 100%;
        margin-left: -5px; }        

    .ellipsis:after {
        content: "\02026";  

        box-sizing: content-box;
        -webkit-box-sizing: content-box;
        -moz-box-sizing: content-box;

        float: right; position: relative;
        top: -25px; left: 100%; 
        width: 3em; margin-left: -3em;
        padding-right: 5px;

        text-align: right;

        background: -webkit-gradient(linear, left top, right top,
            from(rgba(255, 255, 255, 0)), to(white), color-stop(50%, white));
        background: -moz-linear-gradient(to right, rgba(255, 255, 255, 0), white 50%, white);           
        background: -o-linear-gradient(to right, rgba(255, 255, 255, 0), white 50%, white);
        background: -ms-linear-gradient(to right, rgba(255, 255, 255, 0), white 50%, white);
        background: linear-gradient(to right, rgba(255, 255, 255, 0), white 50%, white); }
</style>
</head>
<body>
    <div class="ellipsis">
        <div>
            <p>Call me Ishmael.....</p> 
        </div>
    </div>
</body>
</html>

4

Bạn có thể sử dụng -webkit-line-clamptài sản với div.

-webkit-line-clamp: <integer>có nghĩa là đặt số lượng dòng tối đa trước khi cắt nội dung và sau đó hiển thị dấu chấm lửng (…)ở cuối dòng cuối cùng.

div {
  width: 205px;
  height: 40px;
  background-color: gainsboro;
  overflow: hidden;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  
  /* <integer> values */
  -webkit-line-clamp: 2;
}
<div>This is a multi-lines text block, some lines inside the div, while some outside</div>


2
Không chắc chắn tại sao ai đó đã đánh giá thấp câu trả lời này. Hỗ trợ trình duyệt tính đến tháng 3 năm 2020 là khá tốt - 95% caniuse.com/#search=line-clamp
Yulian

2

Đây là một giải pháp JavaScript vanilla mà bạn có thể sử dụng trong một nhúm:

// @param 1 = element containing text to truncate
// @param 2 = the maximum number of lines to show
function limitLines(el, nLines) {
  var nHeight,
    el2 = el.cloneNode(true);
  // Create clone to determine line height
  el2.style.position = 'absolute';
  el2.style.top = '0';
  el2.style.width = '10%';
  el2.style.overflow = 'hidden';
  el2.style.visibility = 'hidden';
  el2.style.whiteSpace = 'nowrap';
  el.parentNode.appendChild(el2);
  nHeight = (el2.clientHeight+2)*nLines; // Add 2 pixels of slack
  // Clean up
  el.parentNode.removeChild(el2);
  el2 = null;
  // Truncate until desired nLines reached
  if (el.clientHeight > nHeight) {
    var i = 0,
      imax = nLines * 35;
    while (el.clientHeight > nHeight) {
      el.innerHTML = el.textContent.slice(0, -2) + '&hellip;';
      ++i;
      // Prevent infinite loop in "print" media query caused by
      // Bootstrap 3 CSS: a[href]:after { content:" (" attr(href) ")"; }
      if (i===imax) break;
    }
  }
}

limitLines(document.getElementById('target'), 7);
#test {
  width: 320px;
  font-size: 18px;
}
<div id="test">
  <p>Paragraph 1</p>
  <p id="target">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
  <p>Paragraph 3</p>
</div>

Bạn có thể chơi xung quanh với nó trong codepen dưới đây. Hãy thử thay đổi kích thước phông chữ trong bảng CSS và thực hiện một chỉnh sửa nhỏ trong bảng HTML (ví dụ: thêm một khoảng trắng ở đâu đó) để cập nhật kết quả. Bất kể kích thước phông chữ, đoạn giữa phải luôn được cắt ngắn theo số lượng dòng trong tham số thứ hai được truyền cho limLines ().

Codepen: http://codepen.io/thdoan/pen/BoXbEK


2

EDIT: Đã chuyển qua Shave , đây là plugin JS thực hiện cắt ngắn văn bản nhiều dòng dựa trên chiều cao tối đa nhất định thực sự tốt. Nó sử dụng tìm kiếm nhị phân để tìm điểm phá vỡ tối ưu. Chắc chắn đáng để điều tra.


TRẢ LỜI GỐC:

Tôi đã phải đưa ra một giải pháp vanilla JS cho vấn đề này. Trong trường hợp mà tôi đã làm việc, tôi phải đặt một tên sản phẩm dài thành chiều rộng hạn chế và trên hai dòng; cắt ngắn bằng dấu chấm lửng nếu cần.

Tôi đã sử dụng câu trả lời từ các bài viết SO khác nhau để nấu một cái gì đó phù hợp với nhu cầu của tôi. Chiến lược như sau:

  1. Tính độ rộng ký tự trung bình của biến thể phông chữ cho kích thước phông chữ mong muốn.
  2. Tính chiều rộng của container
  3. Tính số lượng ký tự phù hợp trên một dòng trong vùng chứa
  4. Tính số lượng ký tự để cắt chuỗi dựa trên số lượng ký tự phù hợp trên một dòng và số lượng dòng văn bản được cho là bao bọc.
  5. Cắt bớt văn bản đầu vào dựa trên tính toán trước đó (bao thanh toán cho các ký tự phụ được thêm bởi dấu chấm lửng) và nối "..." vào cuối

Mẫu mã:

/**
 * Helper to get the average width of a character in px
 * NOTE: Ensure this is used only AFTER font files are loaded (after page load)
 * @param {DOM element} parentElement 
 * @param {string} fontSize 
 */
function getAverageCharacterWidth(parentElement, fontSize) {
    var textSample = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*()";
    parentElement = parentElement || document.body;
    fontSize = fontSize || "1rem";
    var div = document.createElement('div');
    div.style.width = "auto";
    div.style.height = "auto";
    div.style.fontSize = fontSize;
    div.style.whiteSpace = "nowrap";
    div.style.position = "absolute";
    div.innerHTML = textSample;
    parentElement.appendChild(div);

    var pixels = Math.ceil((div.clientWidth + 1) / textSample.length);
    parentElement.removeChild(div);
    return pixels;
}

/**
 * Helper to truncate text to fit into a given width over a specified number of lines
 * @param {string} text Text to truncate
 * @param {string} oneChar Average width of one character in px
 * @param {number} pxWidth Width of the container (adjusted for padding)
 * @param {number} lineCount Number of lines to span over
 * @param {number} pad Adjust this to ensure optimum fit in containers. Use a negative value to Increase length of truncation, positive values to decrease it.
 */
function truncateTextForDisplay(text, oneChar, pxWidth, lineCount, pad) {
    var ellipsisPadding = isNaN(pad) ? 0 : pad;
    var charsPerLine = Math.floor(pxWidth / oneChar);
    var allowedCount = (charsPerLine * (lineCount)) - ellipsisPadding;
    return text.substr(0, allowedCount) + "...";
}


//SAMPLE USAGE:
var rawContainer = document.getElementById("raw");
var clipContainer1 = document.getElementById("clip-container-1");
var clipContainer2 = document.getElementById("clip-container-2");

//Get the text to be truncated
var text=rawContainer.innerHTML;

//Find the average width of a character
//Note: Ideally, call getAverageCharacterWidth only once and reuse the value for the same font and font size as this is an expensive DOM operation
var oneChar = getAverageCharacterWidth();

//Get the container width
var pxWidth = clipContainer1.clientWidth;

//Number of lines to span over
var lineCount = 2;

//Truncate without padding
clipContainer1.innerHTML = truncateTextForDisplay(text, oneChar, pxWidth, lineCount);

//Truncate with negative padding value to adjust for particular font and font size
clipContainer2.innerHTML = truncateTextForDisplay(text, oneChar, pxWidth, lineCount,-10);
.container{
  display: inline-block;
  width: 200px;
  overflow: hidden;
  height: auto;
  border: 1px dotted black;
  padding: 10px;
  }
<h4>Untruncated</h4>
<div id="raw" class="container">
This is super long text which needs to be clipped to the correct length with ellipsis spanning over two lines
</div>
<h4>Truncated</h4>
<div id="clip-container-1" class="container">
</div>
<h4>Truncated with Padding Tweak</h4>
<div id="clip-container-2" class="container">
</div>

Tái bút

  1. Nếu việc cắt ngắn chỉ nằm trên một dòng, thì phương thức CSS thuần túy sử dụng văn bản tràn: dấu chấm lửng là gọn gàng hơn
  2. Các phông chữ không có chiều rộng cố định có thể khiến việc cắt xén xảy ra quá sớm hoặc quá muộn (vì các ký tự khác nhau có độ rộng khác nhau). Sử dụng tham số pad giúp giảm thiểu điều này trong một số trường hợp nhưng sẽ không phải là bằng chứng ngu ngốc :)
  3. Sẽ thêm vào các liên kết và tham chiếu đến các bài viết gốc sau khi tôi lấy lại máy tính xách tay (cần lịch sử)

PPS: Chỉ cần nhận ra điều này rất giống với cách tiếp cận như được đề xuất bởi @DanMan và @ st.never. Kiểm tra các đoạn mã cho một ví dụ thực hiện.


2

Giải pháp javascript rất đơn giản. Divs phải được tạo kiểu:

.croppedTexts { 
  max-height: 32px;
  overflow: hidden;
}

Và JS:

var list = document.body.getElementsByClassName("croppedTexts");
for (var i = 0; i < list.length; i++) {
  cropTextToFit(list[i]);
}

function cropTextToFit (o) {
  var lastIndex;
  var txt = o.innerHTML;
  if (!o.title) o.title = txt;

  while (o.scrollHeight > o.clientHeight) {
    lastIndex = txt.lastIndexOf(" ");
    if (lastIndex == -1) return;
    txt = txt.substring(0, lastIndex);
    o.innerHTML = txt + "…";
  }
}

1

Không phải là một câu trả lời chính xác cho câu hỏi, nhưng tôi đã bắt gặp trang này khi cố gắng làm rất giống nhau, nhưng muốn thêm một liên kết để "xem nhiều hơn" thay vì chỉ là một dấu chấm lửng đơn giản. Đây là một hàm jQuery sẽ thêm một liên kết "thêm" vào văn bản đang tràn vào một thùng chứa. Cá nhân tôi đang sử dụng cái này với Bootstrap, nhưng tất nhiên nó sẽ hoạt động mà không có.

Ví dụ thêm ảnh chụp màn hình

Để sử dụng, hãy đặt văn bản của bạn vào một thùng chứa như sau:

<div class="more-less">
    <div class="more-block">
        <p>The long text goes in here</p>
    </div>
</div>

Khi hàm jQuery sau được thêm vào, bất kỳ div nào lớn hơn giá trị điều chỉnh sẽ bị cắt bớt và có thêm liên kết "Khác".

$(function(){
    var adjustheight = 60;
    var moreText = '+ More';
    var lessText = '- Less';
    $(".more-less .more-block").each(function(){
        if ($(this).height() > adjustheight){
            $(this).css('height', adjustheight).css('overflow', 'hidden');
            $(this).parent(".more-less").append
                ('<a style="cursor:pointer" class="adjust">' + moreText + '</a>');
        }
    });
    $(".adjust").click(function() {
        if ($(this).prev().css('overflow') == 'hidden')
        {
            $(this).prev().css('height', 'auto').css('overflow', 'visible');
            $(this).text(lessText);
        }
        else {
            $(this).prev().css('height', adjustheight).css('overflow', 'hidden');
            $(this).text(moreText);
        }
    });
});

Dựa trên điều này, nhưng được cập nhật: http://shakenandstirredweb.com/240/jquery-morless-text


<thở dài> Tôi nghĩ ai đó có thể đánh giá thấp điều này, có lẽ vì đó không phải là câu trả lời chính xác cho câu hỏi. Tuy nhiên, tôi hy vọng ai đó sẽ thấy nó hữu ích, vì tôi không thể thông tin này ở bất cứ nơi nào khác và đây là nơi tôi đã kết thúc sau khi tìm kiếm.
Andy Beverley

1

Plugin jQuery dotdotdot được đề cập hoạt động tốt với góc cạnh:

(function (angular) {
angular.module('app')
    .directive('appEllipsis', [
        "$log", "$timeout", function ($log, $timeout) {
            return {
                restrict: 'A',
                scope: false,
                link: function (scope, element, attrs) {

                    // let the angular data binding run first
                    $timeout(function() {
                        element.dotdotdot({
                            watch: "window"
                        });
                    });
                }
            }

        }
    ]);
})(window.angular);

Đánh dấu tương ứng sẽ là:

<p app-ellipsis>{{ selectedItem.Description }}</p>

1

Bản demo thuần túy (không có jQuery và vòng lặp 'while')

Khi tôi tìm kiếm giải pháp cho vấn đề elip đa dòng, tôi đã ngạc nhiên rằng không có cái nào tốt nếu không có jQuery. Ngoài ra, có một vài giải pháp dựa trên vòng lặp 'while', nhưng tôi nghĩ rằng chúng không hiệu quả và nguy hiểm do khả năng đi vào vòng lặp vô hạn. Vì vậy, tôi đã viết mã này:

function ellipsizeTextBox(el) {
  if (el.scrollHeight <= el.offsetHeight) {
    return;
  }

  let wordArray = el.innerHTML.split(' ');
  const wordsLength = wordArray.length;
  let activeWord;
  let activePhrase;
  let isEllipsed = false;

  for (let i = 0; i < wordsLength; i++) {
    if (el.scrollHeight > el.offsetHeight) {
      activeWord = wordArray.pop();
      el.innerHTML = activePhrase = wordArray.join(' ');
    } else {
      break;
    }
  }

  let charsArray = activeWord.split('');
  const charsLength = charsArray.length;

  for (let i = 0; i < charsLength; i++) {
    if (el.scrollHeight > el.offsetHeight) {
      charsArray.pop();
      el.innerHTML = activePhrase + ' ' + charsArray.join('')  + '...';
      isEllipsed = true;
    } else {
      break;
    }
  }

  if (!isEllipsed) {
    activePhrase = el.innerHTML;

    let phraseArr = activePhrase.split('');
    phraseArr = phraseArr.slice(0, phraseArr.length - 3)
    el.innerHTML = phraseArr.join('') + '...';
  }
}

let el = document.getElementById('ellipsed');

ellipsizeTextBox(el);

1

Có thể khá muộn nhưng sử dụng SCSS bạn có thể khai báo một hàm như:

@mixin clamp-text($lines, $line-height) {
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: $lines;
  line-height: $line-height;
  max-height: unquote('#{$line-height*$lines}em');

  @-moz-document url-prefix() {
    position: relative;
    height: unquote('#{$line-height*$lines}em');

    &::after {
      content: '';
      text-align: right;
      position: absolute;
      bottom: 0;
      right: 0;
      width: 30%;
      height: unquote('#{$line-height}em');
      background: linear-gradient(
        to right,
        rgba(255, 255, 255, 0),
        rgba(255, 255, 255, 1) 50%
      );
    }
  }
}

Và sử dụng nó như:

.foo {
    @include clamp-text(1, 1.4);
}

Nó sẽ cắt văn bản thành một dòng và biết rằng nó là 1,4 chiều cao của dòng. Đầu ra dự kiến ​​là chrome để hiển thị ...ở cuối và FF với một số mờ dần ở cuối

Firefox

nhập mô tả hình ảnh ở đây

Trình duyệt Chrome

nhập mô tả hình ảnh ở đây


1

Tìm thấy giải pháp chỉ dành cho CSS ngắn này trong câu trả lời của Adrien Be :

.line-clamp {
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical; 
  overflow: hidden; 
}

Tính đến tháng 3 năm 2020, hỗ trợ trình duyệt95,3% , không được hỗ trợ trong IE và Opera Mini. Hoạt động trên Chrome, Safari, Firefox và Edge.


0

Bạn có thể không thể làm điều đó (hiện tại?) Nếu không có phông chữ có chiều rộng cố định như Chuyển phát nhanh. Với phông chữ có chiều rộng cố định, mỗi chữ cái chiếm cùng một không gian ngang, do đó bạn có thể đếm các chữ cái và nhân kết quả với kích thước phông chữ hiện tại trong các ví dụ hoặc exs. Sau đó, bạn sẽ chỉ cần kiểm tra có bao nhiêu chữ cái phù hợp trên một dòng, và sau đó phá vỡ nó.

Ngoài ra, đối với các phông chữ không cố định, bạn có thể tạo ánh xạ cho tất cả các ký tự có thể (như i = 2px, m = 5px) và sau đó thực hiện phép toán. Rất nhiều công việc xấu xí mặc dù.


0

Để mở rộng giải pháp của @ DanMan: trong trường hợp sử dụng phông chữ có chiều rộng thay đổi, bạn có thể sử dụng chiều rộng phông chữ trung bình. Điều này có hai vấn đề: 1) một văn bản có quá nhiều W sẽ tràn ra và 2) một văn bản có quá nhiều tôi sẽ bị cắt ngắn trước đó.

Hoặc bạn có thể thực hiện một cách tiếp cận trong trường hợp xấu nhất và sử dụng chiều rộng của chữ "W" (mà tôi tin là rộng nhất). Điều này loại bỏ vấn đề 1 ở trên nhưng tăng cường vấn đề 2.

Một cách tiếp cận khác nhau có thể là: để lại overflow: cliptrong div và thêm phần dấu chấm lửng (có thể là một div hoặc hình ảnh khác) với float: right; position: relative; bottom: 0px;(chưa được kiểm tra). Bí quyết là làm cho hình ảnh xuất hiện phía trên cuối văn bản.

Bạn cũng chỉ có thể hiển thị hình ảnh khi bạn biết nó sẽ tràn ra (giả sử, sau khoảng 100 ký tự)


overflow: clipgì Và bạn mong đợi CSS floatsẽ làm gì?
kapa

0

Với mã này, không cần thêm div trình bao bọc nếu phần tử bị giới hạn chiều cao bởi kiểu chiều cao tối đa.

// Shorten texts in overflowed paragraphs to emulate Operas text-overflow: -o-ellipsis-lastline
$('.ellipsis-lastline').each(function(i, e) {
    var $e = $(e), original_content = $e.text();
    while (e.scrollHeight > e.clientHeight)
        $e.text($e.text().replace(/\W*\w+\W*$/, '…'));
    $e.attr('data-original-content', original_content);
});

Ngoài ra, nó lưu văn bản gốc trong một thuộc tính dữ liệu có thể được hiển thị chỉ bằng các kiểu, ví dụ. trên chuột trên:

.ellipsis-lastline {
    max-height: 5em;
}
.ellipsis-lastline:before {
    content: attr(data-original-content);
    position: absolute;
    display: none;
}
.ellipsis-lastline:hover:before {
    display: block;
}

1
Đó thường là vòng lặp vô hạn.
Atadj

0

Trong kịch bản của tôi, tôi không thể làm việc với bất kỳ chức năng nào được đề cập ở trên và tôi cũng cần cho hàm biết có bao nhiêu dòng để hiển thị bất kể kích thước phông chữ hoặc kích thước vùng chứa.

Tôi dựa trên giải pháp của mình về việc sử dụng phương thức Canvas.measureText (mà là một tính năng HTML5 ) như được giải thích ở đây bởi Domi , vì vậy nó không hoàn toàn là trình duyệt chéo.

Bạn có thể thấy nó hoạt động như thế nào trên fiddle này .

Đây là mã:

var processTexts = function processTexts($dom) {
    var canvas = processTexts .canvas || (processTexts .canvas = document.createElement("canvas"));

    $dom.find('.block-with-ellipsis').each(function (idx, ctrl) {
        var currentLineAdded = false;
        var $this = $(ctrl);

        var font = $this.css('font-family').split(",")[0]; //This worked for me so far, but it is not always so easy.
        var fontWeight = $(this).css('font-weight');
        var fontSize = $(this).css('font-size');
        var fullFont = fontWeight + " " + fontSize + " " + font;
        // re-use canvas object for better performance
        var context = canvas.getContext("2d");
        context.font = fullFont;

        var widthOfContainer = $this.width();
        var text = $.trim(ctrl.innerHTML);
        var words = text.split(" ");
        var lines = [];
        //Number of lines to span over, this could be calculated/obtained some other way.
        var lineCount = $this.data('line-count');

        var currentLine = words[0];
        var processing = "";

        var isProcessing = true;
        var metrics = context.measureText(text);
        var processingWidth = metrics.width;
        if (processingWidth > widthOfContainer) {
            for (var i = 1; i < words.length && isProcessing; i++) {
                currentLineAdded = false;
                processing = currentLine + " " + words[i];
                metrics = context.measureText(processing);
                processingWidth = metrics.width;
                if (processingWidth <= widthOfContainer) {
                    currentLine = processing;
                } else {
                    if (lines.length < lineCount - 1) {
                        lines.push(currentLine);
                        currentLine = words[i];
                        currentLineAdded = true;
                    } else {
                        processing = currentLine + "...";
                        metrics = context.measureText(processing);
                        processingWidth = metrics.width;
                        if (processingWidth <= widthOfContainer) {
                            currentLine = processing;
                        } else {
                            currentLine = currentLine.slice(0, -3) + "...";
                        }
                        lines.push(currentLine);
                        isProcessing = false;
                        currentLineAdded = true;
                    }
                }
            }
            if (!currentLineAdded)
                lines.push(currentLine);
            ctrl.innerHTML = lines.join(" ");
        }
    });
};

(function () {
    $(document).ready(function () {
        processTexts($(document));
    });
})();

Và HTML để sử dụng nó sẽ như thế này:

<div class="block-with-ellipsis" data-line-count="2">
    VERY LONG TEXT THAT I WANT TO BREAK IN LINES. VERY LONG TEXT THAT I WANT TO BREAK IN LINES.
</div>

Mã để có được họ phông chữ khá đơn giản và trong trường hợp của tôi hoạt động, nhưng đối với các kịch bản phức tạp hơn, bạn có thể cần phải sử dụng một cái gì đó dọc theo các dòng này .

Ngoài ra, trong trường hợp của tôi, tôi đang nói cho hàm biết có bao nhiêu dòng sử dụng, nhưng bạn có thể tính toán có bao nhiêu dòng để hiển thị theo kích thước và phông chữ của thùng chứa.


0

Tôi đã tạo một phiên bản để lại nguyên vẹn html. ví dụ jsfiddle

jQuery

function shorten_text_to_parent_size(text_elem) {
  textContainerHeight = text_elem.parent().height();


  while (text_elem.outerHeight(true) > textContainerHeight) {
    text_elem.html(function (index, text) {
      return text.replace(/(?!(<[^>]*>))\W*\s(\S)*$/, '...');
    });

  }
}

$('.ellipsis_multiline').each(function () {
  shorten_text_to_parent_size($(this))
});

CSS

.ellipsis_multiline_box {
  position: relative;
  overflow-y: hidden;
  text-overflow: ellipsis;
}

ví dụ jsfiddle


0

Tôi đã viết một thành phần góc giải quyết vấn đề. Nó phân tách một văn bản nhất định thành các yếu tố nhịp. Sau khi kết xuất, nó sẽ loại bỏ tất cả các phần tử tràn và đặt dấu chấm lửng ngay sau phần tử nhìn thấy cuối cùng.

Ví dụ sử dụng:

<app-text-overflow-ellipsis [text]="someText" style="max-height: 50px"></app-text-overflow-ellipsis>

Bản demo của Stackblitz: https://stackblitz.com/edit/angular-wfdqtd

Thanh phân:

import {
  ChangeDetectionStrategy,
  ChangeDetectorRef,
  Component,
  ElementRef, HostListener,
  Input,
  OnChanges,
  ViewChild
} from '@angular/core';

@Component({
  changeDetection: ChangeDetectionStrategy.OnPush,
  selector: 'app-text-overflow-ellipsis',
  template: `
    <span *ngFor="let word of words; let i = index" [innerHTML]="word + (!endsWithHyphen(i) ? ' ' : '')"></span>
    <span #ellipsis [hidden]="!showEllipsis && !initializing" [class.initializing]="initializing" [innerHTML]="'...' + (initializing ? '&nbsp;' : '')"></span>
  `,
  styles: [`
    :host {
      display: block; 
      position: relative;
    }
    .initializing {
      opacity: 0;
    }
  `
  ]
})

export class TextOverflowEllipsisComponent implements OnChanges {
  @Input()
  text: string;

  showEllipsis: boolean;
  initializing: boolean;

  words: string[];

  @ViewChild('ellipsis')
  ellipsisElement: ElementRef;

  constructor(private element: ElementRef, private cdRef: ChangeDetectorRef) {}

  ngOnChanges(){
    this.init();
  }

  @HostListener('window:resize')
  init(){
    // add space after hyphens
    let text = this.text.replace(/-/g, '- ') ;

    this.words = text.split(' ');
    this.initializing = true;
    this.showEllipsis = false;
    this.cdRef.detectChanges();

    setTimeout(() => {
      this.initializing = false;
      let containerElement = this.element.nativeElement;
      let containerWidth = containerElement.clientWidth;
      let wordElements = (<HTMLElement[]>Array.from(containerElement.childNodes)).filter((element) =>
        element.getBoundingClientRect && element !== this.ellipsisElement.nativeElement
      );
      let lines = this.getLines(wordElements, containerWidth);
      let indexOfLastLine = lines.length - 1;
      let lineHeight = this.deductLineHeight(lines);
      if (!lineHeight) {
        return;
      }
      let indexOfLastVisibleLine = Math.floor(containerElement.clientHeight / lineHeight) - 1;

      if (indexOfLastVisibleLine < indexOfLastLine) {

        // remove overflowing lines
        for (let i = indexOfLastLine; i > indexOfLastVisibleLine; i--) {
          for (let j = 0; j < lines[i].length; j++) {
            this.words.splice(-1, 1);
          }
        }

        // make ellipsis fit into last visible line
        let lastVisibleLine = lines[indexOfLastVisibleLine];
        let indexOfLastWord = lastVisibleLine.length - 1;
        let lastVisibleLineWidth = lastVisibleLine.map(
          (element) => element.getBoundingClientRect().width
        ).reduce(
          (width, sum) => width + sum, 0
        );
        let ellipsisWidth = this.ellipsisElement.nativeElement.getBoundingClientRect().width;
        for (let i = indexOfLastWord; lastVisibleLineWidth + ellipsisWidth >= containerWidth; i--) {
          let wordWidth = lastVisibleLine[i].getBoundingClientRect().width;
          lastVisibleLineWidth -= wordWidth;
          this.words.splice(-1, 1);
        }


        this.showEllipsis = true;
      }
      this.cdRef.detectChanges();

      // delay is to prevent from font loading issues
    }, 1000);

  }

  deductLineHeight(lines: HTMLElement[][]): number {
    try {
      let rect0 = lines[0][0].getBoundingClientRect();
      let y0 = rect0['y'] || rect0['top'] || 0;
      let rect1 = lines[1][0].getBoundingClientRect();
      let y1 = rect1['y'] || rect1['top'] || 0;
      let lineHeight = y1 - y0;
      if (lineHeight > 0){
        return lineHeight;
      }
    } catch (e) {}

    return null;
  }

  getLines(nodes: HTMLElement[], clientWidth: number): HTMLElement[][] {
    let lines = [];
    let currentLine = [];
    let currentLineWidth = 0;

    nodes.forEach((node) => {
      if (!node.getBoundingClientRect){
        return;
      }

      let nodeWidth = node.getBoundingClientRect().width;
      if (currentLineWidth + nodeWidth > clientWidth){
        lines.push(currentLine);
        currentLine = [];
        currentLineWidth = 0;
      }
      currentLine.push(node);
      currentLineWidth += nodeWidth;
    });
    lines.push(currentLine);

    return lines;
  }

  endsWithHyphen(index: number): boolean {
    let length = this.words[index].length;
    return this.words[index][length - 1] === '-' && this.words[index + 1] && this.words[index + 1][0];
  }
}

0

Ở đây tôi đã làm một thư viện khác với thuật toán nhanh hơn. Hãy kiểm tra:

https://github.com/i-ahmed-biz/fast-ellipsis

Để cài đặt bằng Bower:

bower install fast-ellipsis

Để cài đặt bằng npm:

npm install fast-ellipsis 

Hy vọng bạn thích!


-2

không chắc đây có phải là thứ bạn đang tìm kiếm hay không, nó sử dụng min-height thay vì height.

    <div id="content" style="min-height:10px;width:190px;background:lightblue;">
    <?php 
        function truncate($text,$numb) {
            // source: www.kigoobe.com, please keep this if you are using the function
            $text = html_entity_decode($text, ENT_QUOTES);
            if (strlen($text) > $numb) {
                $text = substr($text, 0, $numb);
                $etc = "..."; 
                $text = $text.$etc;
            } 
            $text = htmlentities($text, ENT_QUOTES);
            return $text;
        }
        echo truncate("this is a multi-lines text block, some lines inside the div, while some outside", 63);
    ?>
    </div>

4
Vấn đề là số 63 trong mã của bạn, nếu số đó được biết thì mọi thứ trở nên dễ dàng, chỉ cần một chức năng cắt ngắn thực hiện công việc này, như mã của bạn. Tuy nhiên, làm thế nào để biết số? Nói cách khác, làm thế nào để biết văn bản sẽ bị ngắt dòng ở đâu? Nếu câu hỏi này có thể được trả lời, thì vấn đề có thể được giải quyết một cách đơn giản theo logic "1, tính số; 2, cắt ngắn"
Edward

-3

Func rất đơn giản sẽ làm.

Chỉ thị:

  $scope.truncateAlbumName = function (name) {
    if (name.length > 36) {
      return name.slice(0, 34) + "..";
    } else {
      return name;
    }
  };

Lượt xem:

<#p>{{truncateAlbumName(album.name)}}<#/p>

3
Như chúng ta đã thảo luận dưới các câu trả lời khác, vấn đề trong mã của bạn là số 36. Khác với việc làm cho mã của bạn cụ thể theo chiều rộng vùng chứa nhất định, nó cũng không chính xác: với phông chữ không có chiều rộng cố định, có thể có sự khác biệt lớn giữa các chữ cái . Xem iiiiiiiiiivs MMMMMMMMMM(với phông chữ hiện tại không hiển thị mặc dù: D).
kapa
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.