开发者

Jquery - Truncate Text by Line (not by character count)

I need a Jquery script to truncate a text paragraph by line (not by character count).

I would like to achieve an evenly truncated text-block. It should have a "more" and "less" link to expand and shorten the text paragraph. My text paragraph is wrapped in a div with a class, like this:

<div c开发者_开发百科lass="content">
<h2>Headline</h2>
<p>The paragraph Text here</p>
</div>

The closest solution i could find on SOF is the one below (but it`s for textarea element and does not work for me): Limiting number of lines in textarea

Many thanks for any tips. Ben


For a basic approach, you could take a look at the line-height CSS property and use that in your calculations. Bear in mind that this approach will not account for other inline elements that are larger than that height (e.g. images).

If you want something a bit more advanced, you can get the information about each line using getClientRects() function. This function returns a collection of TextRectangle objects with width, height and offset for each one.

See this answer here for an example (albeit an unrelated goal) of how getClientRects() works.


Update, had a bit of time to come back and update this answer with an actual example. It's basic, but you get the idea:

http://jsbin.com/ukaqu3/2

A couple of pointers:

  • The collection returned by getClientRects is static, it won't update automatically if the containing element's dimensions change. My example works around this by capturing the window's resize event.

  • For some strange standards-compliance reason that I'm not understanding, the element you call getClientRects on must be an inline element. In the example I have, I use a container div with the text in another div inside with display: inline.


I made this little jQuery code to allow me truncate text blocks by line (via CSS classes), feel free to use and comment it.

Here is the jsFiddle, which also include truncate functions by char count or word count. You can see that currently, resize the window won't refresh the block display, I'm working on it.

/*
*   Truncate a text bloc after x lines
*   <p class="t_truncate_l_2">Lorem ipsum magna eiusmod sit labore.</p>
*/  
$("*").filter(function () { 
    return /t_truncate_l_/.test($(this).attr('class')); 
}).each(function() {
    var el = $(this);
    var content = el.text();
    var classList = el.attr('class').split(/\s+/);
    $.each(classList, function(index, item){
        if(/^t_truncate_l_/.test(item)) {
            var n = item.substr(13);
            var lineHeight = parseInt(el.css('line-height'));
            if(lineHeight == 1 || el.css('line-height') == 'normal')
                lineHeight = parseInt(el.css('font-size')) * 1.3;
            var maxHeight = n * lineHeight;
            var truncated = $.trim(content);
            var old; 
            if(el.height() > maxHeight)
                truncated += '...';
            while(el.height() > maxHeight && old != truncated) {
                old = truncated;
                truncated = truncated.replace(/\s[^\s]*\.\.\.$/, '...'); 
                el.text(truncated);
            }
        }
    });
});


why not make the p element with overflow: hidden; give fixed line height, caluclate the height of the div so id contains exactly the number of lines you require and the only change the height of the p from javascript.

p{
    overflow:hidden;
    line-height:13px;
    height:26px; /* show only 2 rows */
}
<script type="text/javascript">
    function seeMoreRows(){
        $(p).height("52px");
    }
</script>


I made a small module that works with pure text content, no nested tags and no css-padding on the text-containing element is allowed (but this functionality could easily be added).

The HTML:

<p class="ellipsis" data-ellipsis-max-line-count="3">
    Put some multiline text here
</p>

The Javascript/Jquery:

( function() {

$(document).ready(function(){
    store_contents();
    lazy_update(1000);
});

// Lazy update saves performance for other tasks...
var lazy_update = function(delay) {

    window.lazy_update_timeout = setTimeout(function(){

        update_ellipsis();

        $(window).one('resize', function() {
            lazy_update(delay);
        });

    }, delay);
}

var store_contents = function(){

    $('.ellipsis').each(function(){
        var p = $(this);
        p.data('ellipsis-storage', p.html());
    });
}

var update_ellipsis = function(){

    $('.ellipsis').each(function(){

        var p = $(this);
        var max_line_count = p.data('ellipsis-max-line-count');
        var line_height = p.html('&nbsp').outerHeight();
        var max_height = max_line_count*line_height;
        p.html(p.data('ellipsis-storage'));
        var p_height = p.outerHeight();

        while(p_height > max_height){

            var content_arr = p.html().split(' ');
            content_arr.pop();
            content_arr.pop();
            content_arr.push('...');
            p.html(content_arr.join(' '));
            p_height = p.outerHeight();
        }
    });
}

} )();

I hope you like it!


If you used a monospaced font, you'd have a shot at this working, as you'd have a good idea how many letters fit onto each line, for an element of a defined width. However, if a word breaks across lines, then this might get tricky..

e: found another question which is basically what you're after - they didn't really have a resolution either, but to my mind, the line-height and element height seems closest.

"How can I count text lines inside a dom element"


tl;dr - set a height on your container div and then use the jQuery dotdotdot plugin

Was about to make @Andy E's awesome example into a plugin, but then realized https://github.com/BeSite/jQuery.dotdotdot could pull this off. Our use case is we want to show one line on desktop widths and two lines on mobile/tablet.

Our CSS will just set the container div to the equivalent of one or two line-height's accordingly and then the dotdotdot plugin appears to handle the rest.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜