source

DOM 요소 내부의 텍스트 라인을 세는 방법은 무엇입니까?내가 할 수 있을까?

factcode 2023. 9. 26. 22:35
반응형

DOM 요소 내부의 텍스트 라인을 세는 방법은 무엇입니까?내가 할 수 있을까?

예를 들어 디브 안에서 선을 세는 방법이 있는지 궁금합니다.우리에게 이런 디브가 있다고 치자.

<div id="content">hello how are you?</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");

패딩과 선간 간격도 고려해야 합니다.

편집

라인 높이를 명시적으로 설정하는 완전한 자체 테스트:

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>

요소의 줄 수를 세는 데 사용할 수 있는 getClientRects() 함수를 확인합니다.여기 사용 방법의 예가 있습니다.

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

javascript DOM 객체를 반환합니다.이렇게 하면 선의 양을 알 수 있습니다.

var amount_of_lines = message_lines.length;

몇 가지 유의할 점은 포함 요소가 인라인인 경우에만 작동하지만, 포함하는 인라인 요소를 블록 요소로 둘러싸서 너비를 다음과 같이 제어할 수 있습니다.

console.log(  message_container.getClientRects().length  )
<div style="display:inline;" id="message_container">
  ..Text of the post..<br>
  nice ha?
</div>

그런 스타일은 하드코딩을 추천하지 않지만요.단지 예시적인 목적일 뿐입니다.

한 가지 해결책은 스크립트를 사용하여 모든 단어를 스팬 태그에 둘러싸는 것입니다.그런 다음 주어진 스팬 태그의 Y 차원이 직전 태그의 Y 차원보다 작으면 줄 바꿈이 발생한 것입니다.

저는 여기 있는 것과 다른 질문들에 대한 답에 만족하지 않았습니다.의 답변에는가 소요되지 padding아니면border입니다,면을 box-sizing뿐만 아니라.저의 답변은 여기와 여러 가지 기술과 다른 스레드를 결합하여 제가 만족할 만한 해결책을 얻습니다.

완벽하지 않습니다.에 대한 할 수 line-height(예를 들면normal아니면inherit 할 뿐입니다.font-sizey1.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, Berdana 등 모든 일반 글꼴로 작업합니다.글꼴로 테스트합니다.

예:

<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에서 이 페이지를 열고 다양한 창 너비를 새로 고치고 첫 번째 요소의 줄 수가 어떻게 변하는지 확인합니다.그 페이지에 있는 자바스크립트의 주요 내용은 다음과 같습니다.

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

안타깝게도 파이어폭스는 항상 요소당 하나의 클라이언트 직사각형을 반환하고 IE8도 마찬가지입니다. (Martin Honnen의 페이지는 IE가 IE 호환 보기로 렌더링하기 때문에 오늘 작동합니다. IE8에서 F12를 누르면 다른 모드로 재생됩니다.)

슬프네요.파이어폭스가 마이크로소프트의 유용한 스펙을 제치고 승리한 것은 다시 한번 말 그대로지만 가치 없는 구현인 것 같습니다.아니면 새로운 getClientRects가 개발자에게 도움이 될 수 있는 상황을 놓치나요?

위에서 가이패덕의 답변을 보면, 이건 제게 맞는 것 같습니다.

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

여기서의 비결은 선 높이를 너무 높여 글꼴을 렌더링하는 방식으로 브라우저/OS 차이를 "삼켜버리는" 것입니다.

다양한 스타일과 다양한 글꼴 크기 / 패밀리로 확인해보니 (저의 경우에는 문제가 되지 않았기 때문에), 솔루션에 쉽게 추가할 수 있는 패딩입니다.

아니요, 믿을 수 없습니다.알 수 없는 변수가 너무 많습니다.

  1. 어떤 OS(다양한 DPI, 글꼴 변형 등)?
  2. 그들은 눈이 멀어서 글자 크기가 커집니까?
  3. 웹킷 브라우저에서는 실제로 텍스트 상자 크기를 원하는 대로 조정할 수 있습니다.

리스트는 계속됩니다.언젠가 자바스크립트로 확실하게 이 일을 해낼 수 있는 그런 방법이 있기를 바라지만, 그날이 오기 전까지 당신은 운이 없습니다.

저는 이런 종류의 대답이 싫고 누군가가 제가 틀렸다는 것을 증명해 주었으면 좋겠습니다.

길이를 쪼개서 줄을 끊어야 합니다.

업데이트: 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클라이언트를 이렇게 돌려주고 라인을 받기를 원한다면 다음과 같은 기능을 사용합니다.

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 에디터를 개발할 때 라인 번호를 계산하는 방법을 찾았습니다.주요 방법은 다음과 같습니다.

  1. IE에서 getBoundingClientRects를 호출할 수 있으며 각 행을 직사각형으로 반환합니다.

  2. 웹킷이나 새로운 표준 html 엔진에서는 각 요소나 노드의 클라이언트 직사각형을 반환합니다. 이 경우 각 직사각형을 비교할 수 있습니다. 즉, 각 직사각형이 가장 커야 하므로 직사각형의 높이가 더 작다는 것을 무시할 수 있습니다(직사각의 위가 그것보다 작고 아래가 더 크다면 조건은 참입니다).

그럼 테스트 결과를 보겠습니다.

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

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

다음 솔루션을 사용해 보십시오.

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. 브라우저에서 텍스트 렌더링 수준이 너무 낮아서 자바스크립트에서 직접 쿼리할 수 없습니다.CSS :: 첫 번째 줄 의사 선택기도 다른 선택기처럼 동작하지 않습니다(예를 들어 첫 번째 줄을 제외한 모든 사용자에게 스타일링을 적용할 수 없습니다).

  2. 줄 수를 계산하는 방법에는 컨텍스트가 큰 역할을 합니다.예를 들어, 대상 요소의 계층 구조에서 선 높이를 명시적으로 설정하지 않은 경우 "정상"을 선 높이로 반환할 수 있습니다.가,다를 도 있습니다.box-sizing: border-box따라서 패딩의 대상이 됩니다.

제 접근 방식은 라인 높이를 직접 제어하고 박스 사이징 방법을 인수분해함으로써 #2를 최소화하여 보다 결정론적인 결과를 도출합니다.

정당화되지 않은 텍스트의 여러 행에 걸쳐 있는 링크처럼 다음을 사용하면 행 개수와 각 행의 모든 좌표를 얻을 수 있습니다.

var rectCollection = object.getClientRects();

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

이것은 각 선이 아주 조금이라도 다를 것이기 때문에 효과가 있습니다.그것들이 있는 한, 그것들은 렌더러에 의해 다른 "직각"으로 그려집니다.

요소 높이와 요소 높이를 비교할 수 있습니다.line-height: 0

function lineCount(elm) {
      const originalStyle = elm.getAttribute('style')
      
      // normalize 
      elm.style.padding = 0
      elm.style.border = 0
      
      // measure
      elm.style.lineHeight = 1
      const totalHeight = elm.offsetHeight
      elm.style.lineHeight = 0
      const singleLineHeight = elm.scrollHeight * 2
      
      const lineCount = Math.round(totalHeight / singleLineHeight)
      
      // undo above style changes
      elm.setAttribute('style', originalStyle)
      
      return (isNaN(lineCount) || singleLineHeight == 0) ? 0 : lineCount
}

function printElmLineCount(elm){
  console.log(
     lineCount(elm)
  )
}
p{ border:2em black solid ; padding:1em; line-height: 3em; }
<p contentEditable id='elm'>
  one<br>
  two<br>
  three
</p>

<button onclick='printElmLineCount(elm)'>Get lines count</button>

가장 쉬운 방법은 선 높이를 계산하여 요소 높이로 나누는 것입니다.이 코드는 모든 종류의 요소에 대해 작동합니다.

function getStyle(el,styleProp)
{
    var x = el;
    if (x.currentStyle)
        var y = x.currentStyle[styleProp];
    else if (window.getComputedStyle)
        var y = document.defaultView.getComputedStyle(x,null).getPropertyValue(styleProp);
    return y;
}
function calculateLineHeight (element) {

  var lineHeight = parseInt(getStyle(element, 'line-height'), 10);
  var clone;
  var singleLineHeight;
  var doubleLineHeight;

  if (isNaN(lineHeight)) {
    clone = element.cloneNode();
    clone.innerHTML = '<br>';
    element.appendChild(clone);
    singleLineHeight = clone.offsetHeight;
    clone.innerHTML = '<br><br>';
    doubleLineHeight = clone.offsetHeight;
    element.removeChild(clone);
    lineHeight = doubleLineHeight - singleLineHeight;
  }

  return lineHeight;
}

function getNumlines(el){return Math.ceil(el.offsetHeight / calculateLineHeight (el))}



console.log(getNumlines(document.getElementById('g1')))
.Text{font-size: 28px;}
@media screen and (max-width: 780px) {
            .Text{font-size: 50px;}
        }
<div><span class="Text" id="g1" >
                This code works for any Kind of elements: bla blo bli bla blo bli bla blo bli bla blo bli bla blo bli bla blo bli bla blo bli bla blo bli bla blo bli bla blo bli bla blo bli bla blo bli bla blo bli bla blo bli bla blo bli bla blo bli bla blo bli bla blo bli bla blo bli </span>
        </div>

내 솔루션(중복될 수 있음): 이 요소를 이제 래핑하여 선을 계산합니다.높이를 계산한 다음 선을 하나씩 계산합니다.높이/선 높이

function getLineInfo(root: HTMLElement): {
  lineNumber: number;
  lineHeight: number;
  elHeight: number;
} {
  const oldOverFlow = root.style.overflow;
  const oldWhiteSpace = root.style.whiteSpace;

  root.style.overflow = "hidden";
  root.style.whiteSpace = "nowrap";

  const lineHeight = root.offsetHeight;
  root.style.overflow = oldOverFlow;
  root.style.whiteSpace = oldWhiteSpace;

  const lineNumber = Math.round(root.offsetHeight / lineHeight);

  return {
    lineNumber: lineNumber,
    lineHeight,
    elHeight: root.offsetHeight,
  };
}

요소의 줄 바꿈 수를 셀 수 있습니다.innerText, 다음과 같이:

const text = anyDivElement.innerText;
const lines = text.split(/\r\n|\r|\n/).length;

getClientRects()를 사용하여 테스트가 잘 되지 않은 또 다른 간단한 솔루션:

export function getLineInfo(root: HTMLElement): {
  lineNumber: number;
  lineHeight: number;
  elHeight: number;
} {
  const test = document.createElement("span");
  test.textContent = " ";

  root.appendChild(test);
  const first = test.getClientRects();
  root.insertBefore(test, root.firstChild);
  const second = test.getClientRects();

  const lineHeight = first[0].y - second[0].y;

  test.remove();

  const lastPadding = lineHeight - first[0].height;
  const offsetHeight = first[0].bottom - second[0].top + lastPadding;

  const lineNumber = Math.round(offsetHeight / lineHeight);

  return {
    lineNumber: lineNumber,
    lineHeight,
    elHeight: offsetHeight,
  };
}

React 및 Next.js의 경우 개인 유틸리티 보관 count-linees-element.ts를 만듭니다.

export function countLines(id: string) {

    if (!process.browser || !window || !id) {
      return 0;
    }

    const target = document.getElementById(id);

    if(!target) {
      return 0
    }

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

    return lines;
  }```

언급URL : https://stackoverflow.com/questions/783899/how-can-i-count-text-lines-inside-an-dom-element-can-i

반응형