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

我想知道是否有一种方法来计数线内的行例如。 说我们有这样一个div:

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

div取决于许多因素,可以有一个,或两个,甚至四个文本行。 脚本有什么方法可以知道吗?

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

如果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"); 

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

编辑

完全独立的testing,明确设置行高:

 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> 

一种解决方法是使用脚本将每个单词放在span标签中。 那么如果一个给定的span标签的Y维度小于它的直接前辈,那么就会出现换行符。

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

我不满意这里和其他问题的答案。 评分最高的答案没有考虑paddingborder ,因此显然也忽略了box-sizing 。 我的答案结合了一些技巧在这里和其他线程,以得到一个解决scheme,我的满意。

它不是完美的:当没有数值能够被检索的line-height (例如normalinherit ),它只是使用font-size大小乘以1.2 。 也许其他人可以build议一种可靠的方法来检测这些情况下的像素值。

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

jsFiddle玩耍和testing。 也在下面内联。

 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> 

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

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

对我来说不幸的是,Firefox总是返回一个客户端矩形每个元素,IE8现在也一样。 (Martin Honnen的网页今天工作,因为IE浏览器在IE浏览器视图中呈现;按IE8中的F12以不同的模式播放。

这真是难过;这真是伤心。 看起来Firefox又一次毫无价值地实现了这个规范,赢得了微软有用的一个。 还是我错过了新的getClientRects可以帮助开发人员的情况?

查看函数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> 

虽然我不build议硬编码这样的风格。 这仅仅是为了举例。

克隆容器对象并写入2个字母并计算高度。 这将返回所有应用的样式,行高等的真实高度。现在,计算高度对象/字母的大小。 在jQuery中,高度除了填充,边距和边框,计算每一行的实际高度是很好的:

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

如果您使用每个字母的高度不同的罕见字体,这不起作用。 但与所有正常的字体,如Arial,单声道,漫画,Verdana等,与您的字体testing。

例:

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

结果: 6 Lines

适用于所有浏览器,没有罕见的function。

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

不,不可靠。 有太多未知variables

  1. 什么操作系统(不同的DPI,字体变化等…)?
  2. 他们的字体大小是否因为实际上是盲目的?
  3. 哎呀,在webkit浏览器中,您实际上可以调整文本框的大小以满足您的心愿。

名单继续。 有一天,我希望能有这样一个方法可靠地完成这个JavaScript,但直到那一天来,你的运气。

我讨厌这些答案,我希望有人能certificate我错了。

基于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); } 

这里的诀窍是要增加行高,以便能够渲染任何浏览器/操作系统的差异,

检查它与各种不同的风格和不同的字体大小/家庭只是它没有考虑到的事情(因为在我的情况下没有关系),是填充 – 可以很容易地添加到解决scheme。

您应该能够分割('\ 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> 

getClientRects像这样返回客户端rects,如果你想获得这些行,使用下面的函数

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

当我开发一个html编辑器时,我find了一个计算行号的方法。 主要的方法是:

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

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

所以让我们看看testing结果:

在这里输入图像描述

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

红色矩形是select边界

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

  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 

继@BobBrunius 2010的build议,我用jQuery创build了这个。 毫无疑问,这可以得到改善,但可能会有所帮助。

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

试试这个解决scheme

 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/

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

这个问题比看起来更难,但是大部分难题来自两个来源:

  1. 浏览器中的文本渲染过低,要直接从JavaScript中查询。 即使是CSS :: first-line伪select器也不像其他select器那样工作(例如,不能将其反转,例如,将样式应用于除第一行之外的所有其他select器)。

  2. 上下文在如何计算行数方面起着重要作用。 例如,如果未在目标元素的层次结构中显式设置行高,则可能会将“normal”设置为行高。 此外,该元素可能使用box-sizing: border-box ,因此受到填充。

我的方法通过直接控制线高度并考虑盒子大小方法来最大限度地减less#2,从而导致更确定的结果。

你可以比较元素高度和元素高度与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 }