Как я могу считать текстовые строки внутри элемента DOM? Можно Мне?
Мне интересно, есть ли способ подсчета строк внутри div, например. Скажем, у нас есть div вот так:
<div id="content">hello how are you?</div>
в зависимости от многих факторов div может иметь одну, две или даже четыре строки текста. Есть ли способ, чтобы сценарий знал?
другими словами, представлены ли автоматические разрывы в DOM вообще?
16 ответов:
если размер 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");Вам также нужно будет принять во внимание заполнение и межстрочный интервал.
EDIT
полностью автономный тест, явно устанавливая высоту строки:
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 с помощью скрипта. Затем, если размер Y данного тега span меньше, чем у его непосредственного предшественника, то произошел разрыв строки.
проверить функцию 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>хотя я не рекомендую жестко кодировать стиль таким образом. Это просто для примера.
Я не был удовлетворен ответами здесь и на другие вопросы. Самый высокий рейтинг ответ не принимает
paddingилиborderво внимание, и поэтому, очевидно, игнорируетbox-sizingкак хорошо. Мой ответ сочетает в себе некоторые методы здесь и на других потоках, чтобы получить решение, которое работает к моему удовлетворению.это не идеально: когда ни одно числовое значение не удалось получить для
line-height(например,normalилиinherit), он просто используетfont-sizeумножить на1.2. Возможно, кто-то еще может предложить надежный способ определения значения пикселя в этих случаях.кроме этого, он был в состоянии правильно обрабатывать большинство стилей и случаев, которые я бросил на него.
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>
клонировать объект контейнера и написать 2 буквы и вычислить высоту. Это возвращает реальную высоту со всеми примененными стилями, высотой линии и т. д. Теперь вычислите высоту объекта / размер буквы. В Jquery высота превосходит заполнение, поле и границу, это здорово, чтобы вычислить реальную высоту каждой строки:
other = obj.clone(); other.html('a<br>b').hide().appendTo('body'); size = other.height() / 2; other.remove(); lines = obj.height() / size;Если вы используете редкий шрифт с разной высоты каждой буквы, это не работает. Но работает со всеми обычными шрифтами, такими как Arial, mono, comics, Вердана и др. Тест с вашим шрифтом.
пример:
<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работает во всех браузерах без редких функций из стандартов.
проверить:https://jsfiddle.net/gzceamtr/
для тех, кто использует 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); }
Я убежден, что сейчас это невозможно. Но так оно и было.
реализация 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 делает то же самое. (Мартин Страница хоннена работает сегодня, потому что IE отображает ее в представлении IE compat; нажмите F12 в IE8, чтобы играть в разных режимах.)
Это печально. Похоже, что в очередной раз буквальная, но бесполезная реализация Firefox спецификации выиграла у полезной Microsoft. Или я пропустил ситуацию, когда новые getClientRects могут помочь разработчику?
основываясь на ответе 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); }трюк здесь состоит в том, чтобы увеличить высоту строки настолько, что она" проглотит " любые различия браузера / ОС в том, как они отображают шрифты
проверил его с различными стилями и различными размерами шрифтов / семейств единственное, что он не принимает во внимание (так как в моем случае это не имело значения), это обивка - которую можно легко добавить в решение.
нет, не надежно. Просто слишком много неизвестных переменных
- какая ОС (разные DPI, варианты шрифтов и т. д...)?
- Они имеют свой размер шрифта увеличен, потому что они практически слепы?
- черт возьми, в браузерах webkit вы можете изменить размер текстовых полей по своему желанию.
список можно продолжать. Когда-нибудь я надеюсь, что будет такой метод надежного выполнения этого с помощью JavaScript, но до этого дня выходит, вам не повезло.
Я ненавижу такие ответы и я надеюсь, что кто-то может доказать, меня неправильно.
вы должны быть в состоянии разделить ('\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вернуть клиент выпрямляется как этой и если вы хотите получить строки, используйте функцию follow как этой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; }
попробуйте это решение:
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/
попробуйте изменить размер панелей на странице (чтобы сделать правую сторону страницы шире или короче), а затем запустите его снова, чтобы увидеть, что он может надежно определить, сколько строк есть.
эта проблема сложнее, чем кажется, но большая часть трудностей исходит из двух источников:
текст перевода слишком низкий уровень в браузерах для прямого запроса из JavaScript. Даже псевдоселектор CSS:: first-line ведет себя не совсем так, как другие селекторы (вы не можете инвертировать его, например, чтобы применить стиль ко всем но первая строка).
контекст играет большую роль в том, как подсчитать количество строк. Например, если высота строки не была явно задана в иерархии целевого элемента, вы можете получить "нормальный" обратно в качестве высоты строки. В кроме того, элемент может использовать
box-sizing: border-boxи поэтому подлежит обивка.мой подход минимизирует #2, непосредственно контролируя высоту линии и факторинг в методе определения размера коробки, что приводит к более детерминированному результату.
Я нашел способ вычислить номер строки, когда я разрабатываю редактор html. Основной метод заключается в следующем:
в IE вы можете вызвать getBoundingClientRects, он возвращает каждую строку как a прямоугольник
в webkit или новом стандартном HTML-движке он возвращает каждый элемент или клиентские прямоугольники узла, в этом случае вы можете сравнить каждый прямоугольники, я имею в виду каждый должен быть прямоугольник самый большой, так что вы можете игнорировать те прямоугольники, которые высота меньше(если есть прямоугольник сверху меньше, чем он и снизу больше, чем он, условие верно.)
Итак, давайте посмотрим результат теста:
зеленый прямоугольник является самым большим прямоугольником в каждой строке
красный прямоугольник является границей выделения
синий прямоугольник является границей от начала до выделения после расширения, мы видим, что он может быть больше, чем красный прямоугольник, поэтому мы должны проверить дно каждого прямоугольника, чтобы ограничить его, должно быть меньше, чем дно красного прямоугольника.
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 я создал это с помощью 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>
вы можете сравнить высоту элемента и высоту элемента с
line-height: 0function 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 }
в некоторых случаях, как ссылка, охватывающая несколько строк в неоправданном тексте, вы можете получить количество строк и каждую координату каждой строки, Когда вы используете это:
var rectCollection = object.getClientRects();https://developer.mozilla.org/en-US/docs/Web/API/Element/getClientRects
это работает, потому что каждая строка будет отличаться даже чуть-чуть. Пока они есть, они рисуются как другой "прямоугольник" визуализатором.

Comments