找到换行

时间:2010-09-17 19:46:17

标签: javascript jquery html dom text

假设我在一行中有一些随机的文本块。像这样

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

但无论出于何种原因(包含元素的宽度设置,使用文本缩放等),在查看器的屏幕上它显示为两行或更多行。

Lorem ipsum dolor sit amet,

consectetur adipiscing elit.

Lorem ipsum dolor sit

amet, consectetur

adipiscing elit.

有没有办法通过javascript找到那些换行的地方?

无论文本如何显示,

$('p').text()$('p').html()都会返回Lorem ipsum dolor sit amet, consectetur adipiscing elit.

6 个答案:

答案 0 :(得分:26)

好吧,如果你想要的东西非常简单,对你来说可能太无用(如果你在段落中有任何类型的HTML,那么它需要进行重大修改),那么看看这个:

var para = $('p');

para.each(function(){
    var current = $(this);
    var text = current.text();
    var words = text.split(' ');

    current.text(words[0]);
    var height = current.height();

    for(var i = 1; i < words.length; i++){
        current.text(current.text() + ' ' + words[i]);

        if(current.height() > height){
            height = current.height();
            // (i-1) is the index of the word before the text wraps
            console.log(words[i-1]);
        }
    }
});

它可能只是工作非常简单。这样做是通过空格分解文本,然后逐字追加单词,观察元素高度的任何增加,这表示换行。

在这里查看:http://www.jsfiddle.net/xRPYN/2/

答案 1 :(得分:12)

对于像pdf生成这样的用例。

如果分割出现在中间词中,则可以限制每行的字符数,并进行适当调整。

要获得每行更准确的字符,您可以使用等宽字体,然后确定允许的每种字体的每个字符的宽度。然后将字符宽度除以允许的文本行宽的大小,并为该字体提供每行允许的字符数。

你可以使用非等宽字体,但是你必须测量每个字母的宽度 - 呃。一种可以自动进行宽度猜测的方法是使用没有边距或填充的跨度,为每个字体(和大小)添加每个字符,然后测量跨度的宽度并使用它。

我已经完成了代码:

/**
 * jQuery getFontSizeCharObject
 * @version 1.0.0
 * @date September 18, 2010
 * @since 1.0.0, September 18, 2010
 * @package jquery-sparkle {@link http://www.balupton/projects/jquery-sparkle}
 * @author Benjamin "balupton" Lupton {@link http://www.balupton.com}
 * @copyright (c) 2010 Benjamin Arthur Lupton {@link http://www.balupton.com}
 * @license Attribution-ShareAlike 2.5 Generic {@link http://creativecommons.org/licenses/by-sa/2.5/
 */
$.getFontSizeCharObject = function(fonts,sizes,chars){
    var fonts = fonts||['Arial','Times'],
        sizes = sizes||['12px','14px'],
        chars = chars||['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','y','x','z',
                        'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','Y','X','Z',
                        '0','1','2','3','4','5','6','7','8','9','-','=',
                        '!','@','#','$','%','^','&','*','(',')','_','+',
                        '[',']','{','}','\\','|',
                        ';',"'",':','"',
                        ',','.','/','<','>','?',' '],
        font_size_char = {},
        $body = $('body'),
        $span = $('<span style="padding:0;margin:0;letter-spacing:0:word-spacing:0"/>').appendTo($body);

    $.each(fonts, function(i,font){
        $span.css('font-family', font);
        font_size_char[font] = font_size_char[font]||{};
        $.each(sizes, function(i,size){
            $span.css('font-size',size);
            font_size_char[font][size] = font_size_char[font][size]||{};
            $.each(chars,function(i,char){
                if ( char === ' ' ) {
                    $span.html('&nbsp;');
                }
                else {
                    $span.text(char);
                }
                var width = $span.width()||0;
                font_size_char[font][size][char] = width;
            });
        });
    });

    $span.remove();

    return font_size_char;
};

/**
 * jQuery adjustedText Element Function
 * @version 1.0.0
 * @date September 18, 2010
 * @since 1.0.0, September 18, 2010
 * @package jquery-sparkle {@link http://www.balupton/projects/jquery-sparkle}
 * @author Benjamin "balupton" Lupton {@link http://www.balupton.com}
 * @copyright (c) 2010 Benjamin Arthur Lupton {@link http://www.balupton.com}
 * @license Attribution-ShareAlike 2.5 Generic {@link http://creativecommons.org/licenses/by-sa/2.5/
 */
$.fn.adjustedText = function(text,maxLineWidth){
    var $this = $(this),
        font_size_char = $.getFontSizeCharObject(),
        char_width = font_size_char['Times']['14px'],
        maxLineWidth = parseInt(maxLineWidth,10),
        newlinesAt = [],
        lineWidth = 0,
        lastSpace = null;

    text = text.replace(/\s+/g, ' ');

    $.each(text,function(i,char){
        var width = char_width[char]||0;
        lineWidth += width;
        if ( /^[\-\s]$/.test(char) ) {
            lastSpace = i;
        }
        //console.log(i,char,lineWidth,width);
        if ( lineWidth >= maxLineWidth ) {
            newlinesAt.push(lastSpace||i);
            lineWidth = width;
            lastSpace = null;
        }
    });

    $.each(newlinesAt,function(i,at){
        text = text.substring(0,at+i)+"\n"+text.substring(at+i);
    });

    text = text.replace(/\ ?\n\ ?/g, "\n");

    console.log(text,newlinesAt);

    $this.text(text);

    return $this;
};

$(function(){
    var $body = $('body'),
        $textarea = $('#mytext'),
        $btn = $('#mybtn'),
        $div = $('#mydiv');

    if ( $textarea.length === 0 && $div.length === 0 ) {
        $body.empty();

        $textarea = $('<textarea id="mytext"/>').val('(When spoken repeatedly, often three times in succession: blah blah blah!) Imitative of idle, meaningless talk; used sometimes in a slightly derogatory manner to mock or downplay another\'s words, or to show disinterest in a diatribe, rant, instructions, unsolicited advice, parenting, etc. Also used when recalling and retelling another\'s words, as a substitute for the portions of the speech deemed irrelevant.').appendTo($body);
        $div = $('<div id="mydiv"/>').appendTo($body);
        $btn = $('<button id="mybtn">Update Div</button>').click(function(){
            $div.adjustedText($textarea.val(),'300px');
        }).appendTo($body);

        $div.add($textarea).css({
            'width':'300px',
            'font-family': 'Times',
            'font-size': '14px'
        });
        $div.css({
            'width':'auto',
            'white-space':'pre',
            'text-align':'left'
        });
    }

});

答案 2 :(得分:11)

这是我最终使用的内容(随意批评并复制以用于您自己的邪恶目的)。

首先,当用户进行编辑时,它会被$(editableElement).lineText(userInput)分解。

jQuery.fn.lineText = function (userInput) {
   var a = userInput.replace(/\n/g, " \n<br/> ").split(" ");
   $.each(a, function(i, val) { 
      if(!val.match(/\n/) && val!="") a[i] = '<span class="word-measure">' + val + '</span>';
   });
   $(this).html(a.join(" "));
};

换行更换是因为编辑文本框中填充了$(editableElement).text(),忽略了<br/>个标记,但它们仍然会更改显示中以下行的高度以进行排版。这不是最初目标的一部分,只是相当低调的成果。

当我需要提取格式化文本时,我会调用$(editableElement).getLines(),其中

jQuery.fn.getLines = function (){
   var count = $(this).children(".word-measure").length;
   var lineAcc = [$(this).children(".word-measure:eq(0)").text()];
   var textAcc = [];
   for(var i=1; i<count; i++){
      var prevY = $(this).children(".word-measure:eq("+(i-1)+")").offset().top;
      if($(this).children(".word-measure:eq("+i+")").offset().top==prevY){
         lineAcc.push($(this).children(".word-measure:eq("+i+")").text());
   } else {
     textAcc.push({text: lineAcc.join(" "), top: prevY});
     lineAcc = [$(this).children(".word-measure:eq("+i+")").text()];
   }
   }
   textAcc.push({text: lineAcc.join(" "), top: $(this).children(".word-measure:last").offset().top});
   return textAcc;
};

最终结果是一个哈希列表,每个哈希包含一行文本的内容和垂直偏移。

[{"text":"Some dummy set to","top":363},
 {"text":"demonstrate...","top":382},
 {"text":"The output of this","top":420},
 {"text":"wrap-detector.","top":439}]

如果我只想要无格式文字,$(editableElement).text()仍会返回

"Some dummy set to demonstrate... The output of this wrap-detector."

答案 3 :(得分:7)

如果您有更复杂的结构(例如段落中的链接),则上述解决方案无效(例如,您可以在<b><i><a href></a>内设置<p>)。

所以我创建了一个javascript库来检测在这些情况下换行的位置:http://github.com/xdamman/js-line-wrap-detector

我希望这会有所帮助。

答案 4 :(得分:0)

我有一种情况需要在一个范围内包裹每一行。我这样做,以便我可以添加填充高亮效果到文本块。将背景添加到包装文本的span标记只会填充文本块的开头和结尾,每行必须单独包装。

这是我根据上述建议提出的:

$.fn.highlghtWrap = function () {
    this.each( function () {
      var current = $( this );
      var text = current.text();
      var words = text.split( ' ' );
      var line = '';
      var lines = [];

      current.text( words[ 0 ] );
      var height = current.height();
      line = words[ 0 ];
      for ( var i = 1; i < words.length; i++ ) {
        current.text( current.text() + ' ' + words[ i ] );

        if ( current.height() > height ) {
          lines.push( line );
          line = words[ i ];
          height = current.height();
        } else {
          line = line + ' ' + words[ i ];
        }
      }
      lines.push( line );
      current.html( '' );
      $.each( lines, function ( v, a ) {
        current.html( current.html() + '<span>' + a +
          ' </span>' );
      } );
    } );
  }

  $( '.home-top_wrapper h2' ).highlghtWrap();
  $( '.home-top_wrapper p' ).highlghtWrap();

答案 5 :(得分:0)

从概念上讲,一种简单的方法也适用于内部标记以及任意字体和样式的情况,即进行第一遍,将每个单词简单地放入自己的元素(可能是“ SPAN”,也可能是自定义名称,例如“ w”)

然后,您可以使用getBoundingClientRect()进行迭代,以查找“ top”属性的更改位置:

function findBreaks() {
    var words = document.getElementsByTagName('w');
    var lastTop = 0;
    for (var i=0; i<words.length; i++) {
        var newTop = words[i].getBoundingClientRect().top;
        if (newTop == lastTop) continue;
        console.log("new line " + words[i].textContent + " at: " + newTop);
        lastTop = newTop;
    }
}

这听起来很慢,但是除非文档很大,否则您不会注意到。