如何计算DOM元素内的文本行?我可以吗?

时间:2009-04-23 22:58:28

标签: javascript html dom

我想知道是否有办法计算div中的行数。假设我们有这样的div:

<div id="content">hello how are you?</div>

根据许多因素,div可以有一行,两行甚至四行文本。脚本有什么办法可以知道吗?

换句话说,DOM中是否表示自动中断?

16 个答案:

答案 0 :(得分:71)

如果div的大小取决于内容(我假设你的描述就是这种情况)那么你可以使用以下方法检索div的高度:

var divHeight = document.getElementById('content').offsetHeight;

除以字体行高度:

document.getElementById('content').style.lineHeight;

如果尚未明确设置,则获取行高:

var element = document.getElementById('content');
document.defaultView.getComputedStyle(element, null).getPropertyValue("lineHeight");

您还需要考虑填充和行间距。

修改

完全独立的测试,明确设置line-height:

function countLines() {
   var el = document.getElementById('content');
   var divHeight = el.offsetHeight
   var lineHeight = parseInt(el.style.lineHeight);
   var lines = divHeight / lineHeight;
   alert("Lines: " + lines);
}
<body onload="countLines();">
  <div id="content" style="width: 80px; line-height: 20px">
    hello how are you? hello how are you? hello how are you? hello how are you?
  </div>
</body>

答案 1 :(得分:16)

一种解决方案是使用脚本将每个单词括在span标记中。然后,如果给定span标记的Y维度小于其前一个标记的Y维度,则会发生换行。

答案 2 :(得分:12)

查看函数getClientRects(),该函数可用于计算元素中的行数。以下是如何使用它的示例。

var message_lines = $("#message_container")[0].getClientRects();

它返回一个javascript DOM对象。通过这样做可以知道行数:

var amount_of_lines = message_lines.length;

它可以返回每行的高度等等。通过将其添加到脚本中,然后查看控制台日志,可以查看它可以执行的所有操作。

console.log("");
console.log("message_lines");
console.log(".............................................");
console.dir(message_lines);
console.log("");

虽然需要注意的一些事情是它只有在包含元素是内联的情况下才有效,但是你可以使用块元素包围包含内联元素来控制宽度,如下所示:

<div style="width:300px;" id="block_message_container">
<div style="display:inline;" id="message_container">
..Text of the post..
</div>
</div>

虽然我不建议对这种风格进行硬编码。这只是为了举例。

答案 3 :(得分:10)

我对这里和其他问题的答案感到满意。评分最高的答案并未考虑paddingborder,因此也明显忽略了box-sizing。我的答案结合了一些技术和其他线程,以获得一个令我满意的解决方案。

它并不完美:如果无法为line-height检索数值(例如normalinherit),则只使用font-size乘以{ {1}}。在这些情况下,也许其他人可以建议一种可靠的方法来检测像素值。

除此之外,它已经能够正确处理我抛出的大部分风格和案例。

jsFiddle用于游戏和测试。也在下面内联。

&#13;
&#13;
1.2
&#13;
function countLines(target) {
  var style = window.getComputedStyle(target, null);
  var height = parseInt(style.getPropertyValue("height"));
  var font_size = parseInt(style.getPropertyValue("font-size"));
  var line_height = parseInt(style.getPropertyValue("line-height"));
  var box_sizing = style.getPropertyValue("box-sizing");
  
  if(isNaN(line_height)) line_height = font_size * 1.2;
 
  if(box_sizing=='border-box')
  {
    var padding_top = parseInt(style.getPropertyValue("padding-top"));
    var padding_bottom = parseInt(style.getPropertyValue("padding-bottom"));
    var border_top = parseInt(style.getPropertyValue("border-top-width"));
    var border_bottom = parseInt(style.getPropertyValue("border-bottom-width"));
    height = height - padding_top - padding_bottom - border_top - border_bottom
  }
  var lines = Math.ceil(height / line_height);
  alert("Lines: " + lines);
  return lines;
}
countLines(document.getElementById("foo"));
&#13;
div
{
  padding:100px 0 10% 0;
  background: pink;
  box-sizing: border-box;
  border:30px solid red;
}
&#13;
&#13;
&#13;

答案 4 :(得分:7)

克隆容器对象并写入2个字母并计算高度。这将返回所有应用的样式,行高等实际高度。现在,计算高度对象/字母的大小。在Jquery中,高度除了填充,边距和边框之外,计算每条线的实际高度非常棒:

  **  **  
** *  * *
*   **   *
*        *
 *       *
  *     * 
   *   *  
   *   *  
   *****  

4 4

如果您使用每个字母高度不同的稀有字体,则不起作用。但适用于所有普通字体,如Arial,mono,comics,Verdana等。用你的字体测试。

示例:

other = obj.clone();
other.html('a<br>b').hide().appendTo('body');
size = other.height() / 2;
other.remove();
lines = obj.height() /  size;

结果:<div id="content" style="width: 100px">hello how are you? hello how are you? hello how are you?</div> <script type="text/javascript"> $(document).ready(function(){ calculate = function(obj){ other = obj.clone(); other.html('a<br>b').hide().appendTo('body'); size = other.height() / 2; other.remove(); return obj.height() / size; } n = calculate($('#content')); alert(n + ' lines'); }); </script>

适用于所有浏览器,没有超出标准的稀有功能。

检查:https://jsfiddle.net/gzceamtr/

答案 5 :(得分:6)

对于那些使用jQuery http://jsfiddle.net/EppA2/3/

的人
function getRows(selector) {
    var height = $(selector).height();
    var line_height = $(selector).css('line-height');
    line_height = parseFloat(line_height)
    var rows = height / line_height;
    return Math.round(rows);
}

答案 6 :(得分:5)

我确信现在不可能。不过那是。

IE7的getClientRects实现完全符合我的要求。在IE8中打开this page,尝试刷新不同的窗口宽度,并查看第一个元素中的行数如何相应地更改。以下是该页面中javascript的关键行:

var rects = elementList[i].getClientRects();
var p = document.createElement('p');
p.appendChild(document.createTextNode('\'' + elementList[i].tagName + '\' element has ' + rects.length + ' line(s).'));

不幸的是,Firefox总是为每个元素返回一个客户端矩形,而IE8现在也是如此。 (Martin Honnen的页面今天有效,因为IE在IE compat视图中呈现它;在IE8中按F12以使用不同的模式。)

这很难过。看起来Firefox的文字但毫无价值的规范实现再次赢得了微软的实用价值。或者我是否会错过新的getClientRects可以帮助开发人员的情况?

答案 7 :(得分:3)

基于GuyPaddock的答案,这似乎对我有用

function getLinesCount(element) {
  var prevLH = element.style.lineHeight;
  var factor = 1000;
  element.style.lineHeight = factor + 'px';

  var height = element.getBoundingClientRect().height;
  element.style.lineHeight = prevLH;

  return Math.floor(height / factor);
}

这里的诀窍是增加线高度以至于它会吞下&#34;任何浏览器/操作系统在呈现字体方式上的差异

使用各种样式和不同的字体大小/系列进行检查 只有它没有考虑到(因为在我的情况下它并不重要),是填充 - 可以很容易地添加到解决方案。

答案 8 :(得分:2)

不,不可靠。有太多未知变量

  1. 什么操作系统(不同的DPI,字体变体等)?
  2. 他们的字体大小是否因为实际上是盲目的而放大了?
  3. 哎呀,在webkit浏览器中,你可以根据自己的心愿调整文本框的大小。
  4. 列表还在继续。总有一天,我希望有一种方法可以用JavaScript可靠地完成这个,但是直到那一天到来,你的运气不好。

    我讨厌这些答案,我希望有人可以证明我错了。

答案 9 :(得分:1)

你应该能够分割('\ n')。长度并获得换行符。

更新:这适用于FF / Chrome但不适用于IE。

<html>
<head>
<script src="jquery-1.3.2.min.js"></script>
<script>
    $(document).ready(function() {
        var arr = $("div").text().split('\n');
        for (var i = 0; i < arr.length; i++)
            $("div").after(i + '=' + arr[i] + '<br/>');
    });
</script>
</head>
<body>
<div>One
Two
Three</div>
</body>
</html>

答案 10 :(得分:1)

getClientRects返回this之类的客户端,如果您想获取这些行,请使用this等跟随函数

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

答案 11 :(得分:1)

试试这个解决方案:

function calculateLineCount(element) {
  var lineHeightBefore = element.css("line-height"),
      boxSizing        = element.css("box-sizing"),
      height,
      lineCount;

  // Force the line height to a known value
  element.css("line-height", "1px");

  // Take a snapshot of the height
  height = parseFloat(element.css("height"));

  // Reset the line height
  element.css("line-height", lineHeightBefore);

  if (boxSizing == "border-box") {
    // With "border-box", padding cuts into the content, so we have to subtract
    // it out
    var paddingTop    = parseFloat(element.css("padding-top")),
        paddingBottom = parseFloat(element.css("padding-bottom"));

    height -= (paddingTop + paddingBottom);
  }

  // The height is the line count
  lineCount = height;

  return lineCount;
}

你可以在这里看到它:    https://jsfiddle.net/u0r6avnt/

尝试调整页面上的面板大小(使页面的右侧更宽或更短),然后再次运行它以查看它可以可靠地告知有多少行。

这个问题比它看起来更难,但大多数困难来自两个来源:

  1. 在浏览器中文本呈现太低,无法直接从JavaScript查询。甚至CSS ::第一行伪选择器的行为也不像其他选择器那样(你不能反转它,例如,将样式应用于所有但是第一个线)。

  2. 上下文在计算行数方面起着重要作用。例如,如果未在目标元素的层次结构中显式设置line-height,则可能会得到&#34; normal&#34;回到线高。此外,该元素可能正在使用box-sizing: border-box,因此需要填充。

  3. 我的方法通过直接控制线高并将盒子尺寸方法考虑在内来最小化#2,从而产生更确定的结果。

答案 12 :(得分:0)

按照@BobBrunius 2010的建议,我用jQuery创建了这个。毫无疑问,它可以改进,但它可能有所帮助。

$(document).ready(function() {

  alert("Number of lines: " + getTextLinesNum($("#textbox")));

});

function getTextLinesNum($element) {

  var originalHtml = $element.html();
  var words = originalHtml.split(" ");
  var linePositions = [];
        
  // Wrap words in spans
  for (var i in words) {
    words[i] = "<span>" + words[i] + "</span>";
  }
        
  // Temporarily replace element content with spans. Layout should be identical.
  $element.html(words.join(" "));
        
  // Iterate through words and collect positions of text lines
  $element.children("span").each(function () {
    var lp = $(this).position().top;
    if (linePositions.indexOf(lp) == -1) linePositions.push(lp);
  });
        
  // Revert to original html content
  $element.html(originalHtml);
        
  // Return number of text lines
  return linePositions.length;

}
#textbox {
  width: 200px;
  text-align: center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div id="textbox">Lorem ipsum dolor sit amet, consectetuer adipiscing elit,
  <br>sed diam nonummy</div>

答案 13 :(得分:0)

我在开发html编辑器时找到了一种计算行号的方法。 主要方法是:

  1. 在IE中,您可以调用getBoundingClientRects,它将每行返回为 矩形

  2. 在webkit或新标准html引擎中,它返回每个元素或     节点的客户端矩形,在这种情况下,您可以比较每个     矩形,我的意思是每个必须有一个矩形是最大的,所以     你可以忽略那些高度较小的矩形(如果有的话     矩形的顶部比它小,底部比它大,     条件是真的。)

  3. 所以让我们看看测试结果:

    enter image description here

    绿色矩形是每行中最大的矩形

    红色矩形是选择边界

    蓝色矩形是扩展后从开始到选择的边界,我们看到它可能比红色矩形大,所以我们必须检查每个矩形的底部以限制它必须小于红色矩形的底部

            var lineCount = "?";
            var rects;
            if (window.getSelection) {
                //Get all client rectangles from body start to selection, count those rectangles that has the max bottom and min top
                var bounding = {};
                var range = window.getSelection().getRangeAt(0);//As this is the demo code, I dont check the range count
                bounding = range.getBoundingClientRect();//!!!GET BOUNDING BEFORE SET START!!!
    
                //Get bounding and fix it , when the cursor is in the last character of lineCount, it may expand to the next lineCount.
                var boundingTop = bounding.top;
                var boundingBottom = bounding.bottom;
                var node = range.startContainer;
                if (node.nodeType !== 1) {
                    node = node.parentNode;
                }
                var style = window.getComputedStyle(node);
                var lineHeight = parseInt(style.lineHeight);
                if (!isNaN(lineHeight)) {
                    boundingBottom = boundingTop + lineHeight;
                }
                else {
                    var fontSize = parseInt(style.fontSize);
                    if (!isNaN(fontSize)) {
                        boundingBottom = boundingTop + fontSize;
                    }
                }
                range = range.cloneRange();
    
                //Now we have enougn datas to compare
    
                range.setStart(body, 0);
                rects = range.getClientRects();
                lineCount = 0;
                var flags = {};//Mark a flags to avoid of check some repeat lines again
                for (var i = 0; i < rects.length; i++) {
                    var rect = rects[i];
                    if (rect.width === 0 && rect.height === 0) {//Ignore zero rectangles
                        continue;
                    }
                    if (rect.bottom > boundingBottom) {//Check if current rectangle out of the real bounding of selection
                        break;
                    }
                    var top = rect.top;
                    var bottom = rect.bottom;
                    if (flags[top]) {
                        continue;
                    }
                    flags[top] = 1;
    
                    //Check if there is no rectangle contains this rectangle in vertical direction.
                    var succ = true;
                    for (var j = 0; j < rects.length; j++) {
                        var rect2 = rects[j];
                        if (j !== i && rect2.top < top && rect2.bottom > bottom) {
                            succ = false;
                            break;
                        }
                    }
                    //If succ, add lineCount 1
                    if (succ) {
                        lineCount++;
                    }
                }
            }
            else if (editor.document.selection) {//IN IE8 getClientRects returns each single lineCount as a rectangle
                var range = body.createTextRange();
                range.setEndPoint("EndToEnd", range);
                rects = range.getClientRects();
                lineCount = rects.length;
            }
            //Now we get lineCount here
    

答案 14 :(得分:0)

您可以使用line-height: 0

比较元素高度和元素高度
function lineCount(elm) {
  const style = elm.getAttribute('style')
  elm.style.marginTop = 0
  elm.style.marginBottom = 0
  elm.style.paddingTop = 0
  elm.style.paddingBottom = 0
  const heightAllLine = elm.offsetHeight
  elm.style.lineHeight = 0
  const height1line = elm.offsetHeight
  const lineCount = Math.round(heightAllLine / height1line)
  elm.setAttribute('style', style)
  if (isNaN(lineCount)) return 0
  return lineCount
}

答案 15 :(得分:0)

在某些情况下,例如,链接跨越非对齐文本中的多行,您可以使用以下方法获取行数和每行的每个坐标:

var rectCollection = object.getClientRects();

https://developer.mozilla.org/en-US/docs/Web/API/Element/getClientRects

之所以起作用,是因为每一行即使略有不同也会有所不同。只要存在,渲染器就会将它们绘制为不同的“矩形”。