跨浏览器的多行文本溢出,并在固定的宽度和高度内附加了省略号

2020/10/21 13:22 · javascript ·  · 0评论

我为这个问题制作了一个图像,以使其更易于理解。

是否可以在<div>具有固定宽度和多行的上创建省略号

文字溢出

我已经在这里和那里尝试了一些jQuery插件,但是找不到我想要的插件。有什么建议吗?有想法吗?

只是一个基本的想法。

我正在测试以下标记:

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

和CSS:

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

应用此jQuery将实现所需的结果:

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

它反复尝试删除文本的最后一个单词,直到达到所需的大小。由于溢出:隐藏;该过程仍然不可见,即使关闭了JS,结果也保持“视觉上正确”(当然没有“ ...”)。

如果将它与服务器端的合理截断结合在一起(这只留下很小的开销),那么它将更快地运行:)。

同样,这不是一个完整的解决方案,只是一个想法。

更新:添加了jsFiddle演示

尝试使用jQuery.dotdotdot插件。

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

用于“线夹”的JavaScript库

注意,“线夹”也称为“多线块上的椭圆”或“垂直省略号”。


github.com/BeSite/jQuery.dotdotdot


github.com/josephschmitt/Clamp.js


这里还有一些我尚未调查的内容:


CSS线夹解决方案

有一些CSS解决方案,但是最简单的用法-webkit-line-clamp却缺乏对浏览器的支持观看jsfiddle.net/AdrienBe/jthu55v7/上的实时演示

为了使仅使用CSS做到这一点,许多人付出了巨大的努力。查看相关文章和问题:


我会推荐什么

把事情简单化。除非您有大量时间专用于此功能,否则请选择最简单且经过测试的解决方案:简单的CSS或经过良好测试的javascript库。

寻找一些花哨的/复杂的/高度定制的东西,您将为此付出代价。


别人做什么

像Airbnb那样淡出可能是一个很好的解决方案。它可能是基本的CSS和基本的jQuery。实际上,这似乎与CSSTricks上的此解决方案非常相似

AirBnb“了解更多”解决方案

哦,如果您正在寻找设计灵感:

HTML中没有这样的功能,这非常令人沮丧。

我已经开发了一个来处理这个问题。

  • 多行文字溢出:省略号
  • 具有不支持该功能的多行文字:例如SVG,例如Canvas
  • 例如,SVG文本,HTML渲染和PDF导出中的换行符完全相同

查看我的网站以获取屏幕截图,教程和下载链接。

您可以将-webkit-line-clamp属性与一起使用div

-webkit-line-clamp: <integer>这意味着在截断内容之前设置最大行数,然后(…)在最后一行的末尾显示省略号

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>

基于bažmegakapa解决方案的纯JS解决方案,并进行了一些清理,以解决尝试提供小于元素的lineHeight的height / max-height的人员的问题:

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

我有一个效果很好的解决方案,但省略号使用渐变。优点是您不必执行任何JavaScript计算,并且它适用于可变宽度的容器(包括表格单元格)。它使用了几个额外的div,但是很容易实现。

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

编辑:对不起,我不知道链接是不够的。解决方案是在文本周围放置一个div,并设置div的样式以控制溢出。在div内放置另一个具有“渐变”渐变的div,可以使用CSS或图像(适用于旧版IE)进行渐变。渐变从透明到表格单元格的背景色,比省略号宽一点。如果文本很长且溢出,它将进入“淡入淡出” div下方,并看起来“淡出”。如果文本较短,则淡化是不可见的,因此没有问题。通过将容器的高度设置为文本行高度的倍数,可以调整两个容器以显示一行或多行。可以将“淡入淡出” div定位为仅覆盖最后一行。

这是完成此操作的纯CSS方法:http : //www.mobify.com/blog/multiline-ellipsis-in-pure-css/

总结如下:

在此处输入图片说明

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

这是您可以在紧急情况下使用的原始JavaScript解决方案:

// @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>

您可以在下面的代码栏中使用它。尝试在CSS面板中更改字体大小,然后在HTML面板中进行较小的编辑(例如,在某处添加额外的空间)以更新结果。无论字体大小如何,中间段落都应始终截断为传递给limitLines()的第二个参数中的行数。

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

纯JS演示(无jQuery和“ while”循环)

当我搜索多行省略号问题的解决方案时,我惊讶地发现没有jQuery就没有任何好的选择。也有一些基于“ while”循环的解决方案,但是我认为由于进入无限循环的可能性,它们既无效又危险。所以我写了这段代码:

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

编辑:来到了Shave,这是一个JS插件,可以很好地基于给定的max-height进行多行文本截断。它使用二进制搜索来找到最佳断点。绝对值得调查。


原始答案:

对于这个问题,我不得不想出一个普通的JS解决方案。在我从事过的工作中,我不得不将一个长的产品名称设置为有限的宽度并超过两行。如果需要,用省略号将其截断。

我使用了各种SO帖子中的答案来制作适合我需求的内容。该策略如下:

  1. 计算所需字体大小的字体变体的平均字符宽度。
  2. 计算容器的宽度
  3. 计算适合容器中一行的字符数
  4. 根据适合一行的字符数和文本应该换行的行数,计算将字符串截断的字符数。
  5. 根据先前的计算(将因省略号添加的额外字符计算在内)截断输入文本,并在末尾附加“ ...”

代码示例:

/**
 * 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>

PS:

  1. 如果截断仅在一行上,那么使用text-overflow的纯CSS方法:省略号会更整洁
  2. 没有固定宽度的字体可能会导致截断发生得太早或太晚(因为不同的字符具有不同的宽度)。在某些情况下,使用pad参数可以缓解这种情况,但并非万无一失:)
  3. 取回笔记本电脑后,将在原始帖子中添加链接和引用(需要历史记录)

PPS:刚意识到这与@DanMan和@ st.never建议的方法非常相似。检出代码片段以获取实现示例。

非常简单的javascript解决方案。Divs必须设置为fe:

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

和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 + "…";
  }
}

这个问题的答案不是确切的,但是当我尝试做一个非常相似的页面时却遇到了这个页面,但是我想添加一个链接来“查看更多”而不是简单的省略号。这是一个jQuery函数,它将为溢出容器的文本添加“更多”链接。我个人是在Bootstrap上使用它,但是如果没有它,它当然可以工作。

示例更多屏幕截图

若要使用,请按照以下步骤将文本放入容器中:

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

添加以下jQuery函数时,任何大于Adjustheight值的div都会被截断并添加“更多”链接。

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

基于此,但已更新:http : //shakenandstirredweb.com/240/jquery-moreless-text

提到的dotdotdot jQuery插件可与angular配合使用:

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

相应的标记为:

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

也许已经很晚了,但是使用SCSS可以声明一个类似以下的函数:

@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%
      );
    }
  }
}

并像这样使用它:

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

这会将文本截断为一行,并且知道它的行高为1.4。预期的输出是chrome渲染,...最后渲染FF,FF渲染结束时有些冷淡

火狐浏览器

在此处输入图片说明

在此处输入图片说明

Adrien Be的答案中找到了这个仅CSS的简短解决方案

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

截至2020年3月 浏览器的支持95.3% 而不是在IE浏览器和Opera Mini的支撑。适用于Chrome,Safari,Firefox和Edge。

如果没有像Courier这样的固定宽度字体,您可能无法(当前?)进行操作。使用固定宽度的字体时,每个字母都占据相同的水平空间,因此您可以对字母进行计数,然后将结果乘以当前字体大小(以ems或exs为单位)。然后,您只需要测试一行中可以容纳多少个字母,然后将其分解即可。

另外,对于非固定字体,您也许可以为所有可能的字符(例如i = 2px,m = 5px)创建映射,然后进行数学计算。虽然很多丑陋的工作。

要扩展@DanMan的解决方案:在使用可变宽度字体的情况下,可以使用平均字体宽度。这有两个问题:1)W过多的文本会溢出; 2)I过多的文本会被更早地截断。

或者,您可以采用最坏的情况,并使用字母“ W”的宽度(我认为这是最宽的)。这消除了上面的问题1,但加剧了问题2。

一种不同的方法可能是:留overflow: clip在div中并添加带有float: right; position: relative; bottom: 0px;(未嵌套)的省略号部分(可能是另一个div或图像)。诀窍是使图像显示在文本末尾上方。

您也只能在知道图像将要溢出时才显示图像(例如,大约100个字符后)

使用此代码,如果元素的高度受max-height样式限制,则不需要额外的wrapper div。

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

还将原始文本保存在只能使用样式显示的数据属性中。鼠标悬停在:

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

在我的场景中,我无法使用上面提到的任何功能,而且我还需要告诉该功能显示多少行而不管字体大小或容器大小如何。

我根据我的使用的解决方案Canvas.measureText方法(whic是HTML5功能)的说明这里通过多米,所以它不是完全的跨浏览器。

您可以看到它如何在这种提琴上工作

这是代码:

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

和使用它的HTML将是这样的:

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

获得字体系列的代码非常简单,在我的情况下,它可以工作,但是对于更复杂的场景,您可能需要沿这些方向使用一些东西

另外,就我而言,我告诉函数要使用多少行,但是您可以根据容器的大小和字体来计算要显示的行数。

我制作了一个保留html不变的版本。
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;
}

jsfiddle示例

我写了一个解决这个问题的角度组件。它将给定的文本拆分为span元素。渲染后,它将删除所有溢出元素,并将省略号放在最后一个可见元素之后。

用法示例:

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

Stackblitz演示:https ://stackblitz.com/edit/angular-wfdqtd

组件:

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

在这里,我制作了另一个具有更快算法的库。请检查:

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

要使用凉亭安装:

bower install fast-ellipsis

要使用npm安装:

npm install fast-ellipsis 

希望你喜欢!

不知道这是否是您要查找的内容,它使用最小高度而不是高度。

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

很简单的func就可以了。

指示:

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

视图:

<#p>{{truncateAlbumName(album.name)}}<#/p>
本文地址:http://javascript.askforanswer.com/kualiulanqideduoxingwenbenyichubingzaigudingdekuanduhegaoduneifujialeshengluehao.html
文章标签: ,   ,   ,  
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!