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

时间:2022-10-31 11:48:36

I'm wondering if there's a way to count lines inside a div for example. Say we have a div like so:

我想知道是否有一种方法可以计算div中的行数。比如我们有一个div比如:

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

Depending on many factors, the div can have one, or two, or even four lines of text. Is there any way for the script to know?

根据许多因素,div可以有一行、两行甚至四行文本。有没有办法让剧本知道?

In other words, are automatic breaks represented in DOM at all?

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

15 个解决方案

#1


63  

If the div's size is dependent on the content (which I assume to be the case from your description) then you can retrieve the div's height using:

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

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

And divide by the font line height:

并除以字体行高:

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

Or to get the line height if it hasn't been explicitly set:

或未显式设定的线高:

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

You will also need to take padding and inter-line spacing into account.

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

EDIT

编辑

Fully self-contained test, explicitly setting line-height:

完全独立测试,显式设定线高:

function countLines() {
  var divHeight = document.getElementById('content').offsetHeight
  var lineHeight = parseInt(document.getElementById('content').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>

#2


14  

One solution is to enclose every word in a span tag using script. Then if the Y dimension of a given span tag is less than that of it's immediate predecessor then a line break has occurred.

一种解决方案是使用脚本将每个单词包含在span标记中。然后,如果给定span标记的Y维数小于它的前一个标记的Y维数,那么就发生了换行。

#3


6  

For those who use jQuery http://jsfiddle.net/EppA2/3/

对于使用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);
}

#4


6  

I wasnt satisfied with the answers here and on other questions. The highest rated answer doesn't take padding or border into account, and therefore obviously ignores box-sizing as well. My answer combines some techniques here and and on other threads to get a solution that works to my satisfaction.

我对这里和其他问题的答案都不满意。评分最高的答案不考虑填充或边框,因此显然也忽略了方框大小。我的回答结合了这里和其他线程上的一些技术,以得到一个令我满意的解决方案。

It isnt perfect: When no numerical value was able to be retrieved for the line-height (e.g. normal or inherit), it just uses the font-size multiplied by 1.2. Perhaps someone else can suggest a reliable way to detect the pixel value in those cases.

它不是完美的:当不能为行高检索数值时(例如普通值或继承值),它只使用字体大小乘以1.2。也许其他人可以提出一种可靠的方法来检测这些情况下的像素值。

Other than that, it has been able to correctly handle most of the styles and cases I have thrown at it.

除此之外,它还能够正确地处理我抛出的大多数样式和案例。

jsFiddle for playing around and testing. Also inline below.

用于游戏和测试的jsFiddle。下面还内联。

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"));
div
{
  padding:100px 0 10% 0;
  background: pink;
  box-sizing: border-box;
  border:30px solid red;
}
<div id="foo">
x<br>
x<br>
x<br>
x<br>
</div>

#5


5  

I am convinced that it is impossible now. It was, though.

我确信现在是不可能的。不过,这是。

IE7’s implementation of getClientRects did exactly what I want. Open this page in IE8, try refreshing it varying window width, and see how number of lines in the first element changes accordingly. Here’s the key lines of the javascript from that page:

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

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

Unfortunately for me, Firefox always returns one client rectangle per element, and IE8 does the same now. (Martin Honnen’s page works today because IE renders it in IE compat view; press F12 in IE8 to play with different modes.)

不幸的是,Firefox总是每个元素返回一个客户端矩形,而IE8现在也是这样。(Martin Honnen的页面今天仍然有效,因为IE将其呈现在IE compat视图中;按下IE8中的F12,就可以玩不同的模式。

This is sad. It looks like once again Firefox’s literal but worthless implementation of the spec won over Microsoft’s useful one. Or do I miss a situation where new getClientRects may help a developer?

这是可悲的。看来Firefox的规范实现再一次赢得了微软的支持。还是我错过了一个新的getClientRects可以帮助开发人员的情况?

#6


5  

Check out the function getClientRects() which can be used to count the number of lines in an element. Here is an example of how to use it.

检查函数getClientRects(),该函数可用于计算元素中的行数。这里有一个如何使用它的例子。

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

It returns a javascript DOM object. The amount of lines can be known by doing this:

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

var amount_of_lines = message_lines.length;

It can return the height of each line, and more. See the full array of things it can do by adding this to your script, then looking in your console log.

它可以返回每条线的高度,甚至更多。通过将它添加到脚本中,然后查看控制台日志,可以看到它可以做的全部事情。

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

Though a few things to note is it only works if the containing element is inline, however you can surround the containing inline element with a block element to control the width like so:

尽管需要注意的是,它只在包含元素是内联的情况下有效,但是您可以使用块元素将包含的内联元素包围起来,以控制宽度,如下所示:

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

Though I don't recommend hard coding the style like that. It's just for example purposes.

虽然我不推荐这样的硬编码风格。只是举个例子。

#7


5  

Clone the container object and write 2 letters and calculate the height. This return the real height with all style applied, line height, etc. Now, calculate the height object / the size of a letter. In Jquery, the height excelude the padding, margin and border, it is great to calculate the real height of each line:

克隆容器对象,写两个字母并计算其高度。它返回实际的高度,使用所有样式,行高度等等。现在,计算高度对象/字母的大小。在Jquery中,高度优于填充、边距和边框,计算每一行的实际高度非常好:

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

If you use a rare font with different height of each letter, this does not works. But works with all normal fonts, like Arial, mono, comics, Verdana, etc. Test with your font.

如果你使用一种罕见的字体,每个字母的高度都不一样,这是行不通的。但是适用于所有普通字体,如Arial, mono, comics, Verdana等。

Example:

例子:

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

Result: 6 Lines

结果:6行

Works in all browser without rare functions out of standards.

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

Check: https://jsfiddle.net/gzceamtr/

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

#8


3  

based on GuyPaddock's answer from above, this seems to work for me

根据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);
}

the trick here is to increase the line-height so much that it will "swallow" any browser / OS differences in the way that they render fonts

这里的诀窍是增加行高度,这样就会“吞噬”浏览器/操作系统在呈现字体的方式上的差异

Checked it with various stylings and different font sizes / families only thing that it doesn't take into account (since in my case it didnt matter), is the padding - which can easily be added to the solution.

用不同的样式和不同的字体大小/种类检查它,唯一它没有考虑的事情(因为在我的例子中它不重要)是填充——可以很容易地添加到解决方案中。

#9


2  

No, not reliably. There are simply too many unknown variables

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

  1. What OS (different DPIs, font variations, etc...)?
  2. 什么操作系统(不同的DPIs、字体变化等)?
  3. Do they have their font-size scaled up because they are practically blind?
  4. 他们的字体尺寸增大是因为他们实际上是瞎的吗?
  5. Heck, in webkit browsers, you can actually resize textboxes to your heart's desire.
  6. 在webkit浏览器中,你可以根据自己的喜好调整文本框的大小。

The list goes on. Someday I hope there will be such a method of reliably accomplishing this with JavaScript, but until that day comes, your out of luck.

的例子不胜枚举。我希望有一天会有这样一种方法可以用JavaScript可靠地实现这一点,但在那一天到来之前,你运气不佳。

I hate these kinds of answers and I hope someone can prove me wrong.

我讨厌这种回答,我希望有人能证明我错了。

#10


1  

You should be able to split('\n').length and get the line breaks.

你应该能够分裂('\n')。长度和换行时间。

update: this works on FF/Chrome but not IE.

更新:这适用于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>

#11


1  

getClientRects return the client rects like this and if you want to get the lines, use the follow function like this

getClientRects返回这样的客户端,如果您想要得到这些行,请使用如下函数。

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

#12


1  

Try this solution:

试试这个解决方案:

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

You can see it in action here: https://jsfiddle.net/u0r6avnt/

您可以在这里看到它的操作:https://jsfiddle.net/u0r6avnt/。

Try resizing the panels on the page (to make the right side of the page wider or shorter) and then run it again to see that it can reliably tell how many lines there are.

试着调整页面上的面板的大小(使页面的右边更宽或更短),然后再运行一次,看看它能可靠地告诉你有多少行。

This problem is harder than it looks, but most of the difficulty comes from two sources:

这个问题比看上去的要难,但大多数困难来自两个方面:

  1. Text rendering is too low-level in browsers to be directly queried from JavaScript. Even the CSS ::first-line pseudo-selector doesn't behave quite like other selectors do (you can't invert it, for example, to apply styling to all but the first line).

    在浏览器中,文本呈现水平太低,无法直接从JavaScript查询。甚至连CSS::first-line伪选择器的行为也不像其他选择器那样(例如,除了第一行之外,您不能对所有选择器应用样式)。

  2. Context plays a big part in how you calculate the number of lines. For example, if line-height was not explicitly set in the hierarchy of the target element, you might get "normal" back as a line height. In addition, the element might be using box-sizing: border-box and therefore be subject to padding.

    上下文在计算行数的过程中起着很大的作用。例如,如果在目标元素的层次结构中没有显式地设置行高度,您可能会得到“normal”返回为行高度。此外,元素可能使用box- size: border-box,因此受到填充的限制。

My approach minimizes #2 by taking control of the line-height directly and factoring in the box sizing method, leading to a more deterministic result.

我的方法通过直接控制线段高度,并考虑箱形尺寸法,使2最小化,从而得到更确定的结果。

#13


0  

I found a way to calc the line number when I develop a html editor. The primary method is that:

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

  1. In IE you can call getBoundingClientRects, it returns each line as a rectangle

    在IE中,可以调用getBoundingClientRects,它以矩形返回每一行

  2. In webkit or new standard html engine, it returns each element or node's client rectangles, in this case you can compare each rectangles, I mean each there must be a rectangle is the largest, so you can ignore those rectangles that height is smaller(if there is a rectangle's top smaller than it and bottom larger than it, the condition is true.)

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

so let's see the test result:

让我们看看测试结果:

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

The green rectangle is the largest rectangle in each row

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

The red rectangle is the selection boundary

红色矩形是选择边界

The blue rectangle is the boundary from start to selection after expanding, we see it may larger than red rectangle, so we have to check each rectangle's bottom to limit it must smaller than red rectangle's bottom.

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

        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  

Following @BobBrunius 2010 suggestion I created this with jQuery. No doubt it could be improved but it may help some.

按照@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>

#15


0  

You can compare element height and element height with line-height: 0

您可以将元素高度和元素高度与行高度: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
}

#1


63  

If the div's size is dependent on the content (which I assume to be the case from your description) then you can retrieve the div's height using:

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

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

And divide by the font line height:

并除以字体行高:

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

Or to get the line height if it hasn't been explicitly set:

或未显式设定的线高:

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

You will also need to take padding and inter-line spacing into account.

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

EDIT

编辑

Fully self-contained test, explicitly setting line-height:

完全独立测试,显式设定线高:

function countLines() {
  var divHeight = document.getElementById('content').offsetHeight
  var lineHeight = parseInt(document.getElementById('content').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>

#2


14  

One solution is to enclose every word in a span tag using script. Then if the Y dimension of a given span tag is less than that of it's immediate predecessor then a line break has occurred.

一种解决方案是使用脚本将每个单词包含在span标记中。然后,如果给定span标记的Y维数小于它的前一个标记的Y维数,那么就发生了换行。

#3


6  

For those who use jQuery http://jsfiddle.net/EppA2/3/

对于使用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);
}

#4


6  

I wasnt satisfied with the answers here and on other questions. The highest rated answer doesn't take padding or border into account, and therefore obviously ignores box-sizing as well. My answer combines some techniques here and and on other threads to get a solution that works to my satisfaction.

我对这里和其他问题的答案都不满意。评分最高的答案不考虑填充或边框,因此显然也忽略了方框大小。我的回答结合了这里和其他线程上的一些技术,以得到一个令我满意的解决方案。

It isnt perfect: When no numerical value was able to be retrieved for the line-height (e.g. normal or inherit), it just uses the font-size multiplied by 1.2. Perhaps someone else can suggest a reliable way to detect the pixel value in those cases.

它不是完美的:当不能为行高检索数值时(例如普通值或继承值),它只使用字体大小乘以1.2。也许其他人可以提出一种可靠的方法来检测这些情况下的像素值。

Other than that, it has been able to correctly handle most of the styles and cases I have thrown at it.

除此之外,它还能够正确地处理我抛出的大多数样式和案例。

jsFiddle for playing around and testing. Also inline below.

用于游戏和测试的jsFiddle。下面还内联。

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"));
div
{
  padding:100px 0 10% 0;
  background: pink;
  box-sizing: border-box;
  border:30px solid red;
}
<div id="foo">
x<br>
x<br>
x<br>
x<br>
</div>

#5


5  

I am convinced that it is impossible now. It was, though.

我确信现在是不可能的。不过,这是。

IE7’s implementation of getClientRects did exactly what I want. Open this page in IE8, try refreshing it varying window width, and see how number of lines in the first element changes accordingly. Here’s the key lines of the javascript from that page:

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

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

Unfortunately for me, Firefox always returns one client rectangle per element, and IE8 does the same now. (Martin Honnen’s page works today because IE renders it in IE compat view; press F12 in IE8 to play with different modes.)

不幸的是,Firefox总是每个元素返回一个客户端矩形,而IE8现在也是这样。(Martin Honnen的页面今天仍然有效,因为IE将其呈现在IE compat视图中;按下IE8中的F12,就可以玩不同的模式。

This is sad. It looks like once again Firefox’s literal but worthless implementation of the spec won over Microsoft’s useful one. Or do I miss a situation where new getClientRects may help a developer?

这是可悲的。看来Firefox的规范实现再一次赢得了微软的支持。还是我错过了一个新的getClientRects可以帮助开发人员的情况?

#6


5  

Check out the function getClientRects() which can be used to count the number of lines in an element. Here is an example of how to use it.

检查函数getClientRects(),该函数可用于计算元素中的行数。这里有一个如何使用它的例子。

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

It returns a javascript DOM object. The amount of lines can be known by doing this:

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

var amount_of_lines = message_lines.length;

It can return the height of each line, and more. See the full array of things it can do by adding this to your script, then looking in your console log.

它可以返回每条线的高度,甚至更多。通过将它添加到脚本中,然后查看控制台日志,可以看到它可以做的全部事情。

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

Though a few things to note is it only works if the containing element is inline, however you can surround the containing inline element with a block element to control the width like so:

尽管需要注意的是,它只在包含元素是内联的情况下有效,但是您可以使用块元素将包含的内联元素包围起来,以控制宽度,如下所示:

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

Though I don't recommend hard coding the style like that. It's just for example purposes.

虽然我不推荐这样的硬编码风格。只是举个例子。

#7


5  

Clone the container object and write 2 letters and calculate the height. This return the real height with all style applied, line height, etc. Now, calculate the height object / the size of a letter. In Jquery, the height excelude the padding, margin and border, it is great to calculate the real height of each line:

克隆容器对象,写两个字母并计算其高度。它返回实际的高度,使用所有样式,行高度等等。现在,计算高度对象/字母的大小。在Jquery中,高度优于填充、边距和边框,计算每一行的实际高度非常好:

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

If you use a rare font with different height of each letter, this does not works. But works with all normal fonts, like Arial, mono, comics, Verdana, etc. Test with your font.

如果你使用一种罕见的字体,每个字母的高度都不一样,这是行不通的。但是适用于所有普通字体,如Arial, mono, comics, Verdana等。

Example:

例子:

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

Result: 6 Lines

结果:6行

Works in all browser without rare functions out of standards.

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

Check: https://jsfiddle.net/gzceamtr/

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

#8


3  

based on GuyPaddock's answer from above, this seems to work for me

根据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);
}

the trick here is to increase the line-height so much that it will "swallow" any browser / OS differences in the way that they render fonts

这里的诀窍是增加行高度,这样就会“吞噬”浏览器/操作系统在呈现字体的方式上的差异

Checked it with various stylings and different font sizes / families only thing that it doesn't take into account (since in my case it didnt matter), is the padding - which can easily be added to the solution.

用不同的样式和不同的字体大小/种类检查它,唯一它没有考虑的事情(因为在我的例子中它不重要)是填充——可以很容易地添加到解决方案中。

#9


2  

No, not reliably. There are simply too many unknown variables

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

  1. What OS (different DPIs, font variations, etc...)?
  2. 什么操作系统(不同的DPIs、字体变化等)?
  3. Do they have their font-size scaled up because they are practically blind?
  4. 他们的字体尺寸增大是因为他们实际上是瞎的吗?
  5. Heck, in webkit browsers, you can actually resize textboxes to your heart's desire.
  6. 在webkit浏览器中,你可以根据自己的喜好调整文本框的大小。

The list goes on. Someday I hope there will be such a method of reliably accomplishing this with JavaScript, but until that day comes, your out of luck.

的例子不胜枚举。我希望有一天会有这样一种方法可以用JavaScript可靠地实现这一点,但在那一天到来之前,你运气不佳。

I hate these kinds of answers and I hope someone can prove me wrong.

我讨厌这种回答,我希望有人能证明我错了。

#10


1  

You should be able to split('\n').length and get the line breaks.

你应该能够分裂('\n')。长度和换行时间。

update: this works on FF/Chrome but not IE.

更新:这适用于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>

#11


1  

getClientRects return the client rects like this and if you want to get the lines, use the follow function like this

getClientRects返回这样的客户端,如果您想要得到这些行,请使用如下函数。

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

#12


1  

Try this solution:

试试这个解决方案:

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

You can see it in action here: https://jsfiddle.net/u0r6avnt/

您可以在这里看到它的操作:https://jsfiddle.net/u0r6avnt/。

Try resizing the panels on the page (to make the right side of the page wider or shorter) and then run it again to see that it can reliably tell how many lines there are.

试着调整页面上的面板的大小(使页面的右边更宽或更短),然后再运行一次,看看它能可靠地告诉你有多少行。

This problem is harder than it looks, but most of the difficulty comes from two sources:

这个问题比看上去的要难,但大多数困难来自两个方面:

  1. Text rendering is too low-level in browsers to be directly queried from JavaScript. Even the CSS ::first-line pseudo-selector doesn't behave quite like other selectors do (you can't invert it, for example, to apply styling to all but the first line).

    在浏览器中,文本呈现水平太低,无法直接从JavaScript查询。甚至连CSS::first-line伪选择器的行为也不像其他选择器那样(例如,除了第一行之外,您不能对所有选择器应用样式)。

  2. Context plays a big part in how you calculate the number of lines. For example, if line-height was not explicitly set in the hierarchy of the target element, you might get "normal" back as a line height. In addition, the element might be using box-sizing: border-box and therefore be subject to padding.

    上下文在计算行数的过程中起着很大的作用。例如,如果在目标元素的层次结构中没有显式地设置行高度,您可能会得到“normal”返回为行高度。此外,元素可能使用box- size: border-box,因此受到填充的限制。

My approach minimizes #2 by taking control of the line-height directly and factoring in the box sizing method, leading to a more deterministic result.

我的方法通过直接控制线段高度,并考虑箱形尺寸法,使2最小化,从而得到更确定的结果。

#13


0  

I found a way to calc the line number when I develop a html editor. The primary method is that:

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

  1. In IE you can call getBoundingClientRects, it returns each line as a rectangle

    在IE中,可以调用getBoundingClientRects,它以矩形返回每一行

  2. In webkit or new standard html engine, it returns each element or node's client rectangles, in this case you can compare each rectangles, I mean each there must be a rectangle is the largest, so you can ignore those rectangles that height is smaller(if there is a rectangle's top smaller than it and bottom larger than it, the condition is true.)

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

so let's see the test result:

让我们看看测试结果:

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

The green rectangle is the largest rectangle in each row

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

The red rectangle is the selection boundary

红色矩形是选择边界

The blue rectangle is the boundary from start to selection after expanding, we see it may larger than red rectangle, so we have to check each rectangle's bottom to limit it must smaller than red rectangle's bottom.

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

        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  

Following @BobBrunius 2010 suggestion I created this with jQuery. No doubt it could be improved but it may help some.

按照@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>

#15


0  

You can compare element height and element height with line-height: 0

您可以将元素高度和元素高度与行高度: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
}