Найти визуализированные разрывы строк с помощью javascript

У меня такая ситуация:

div { width: 200px }
<div> example example example example example</div>

Текст автоматически переходит на следующую строку при заполнении всей ширины <div>.

Используя javascript, как я могу отображать содержимое в строке выше?

Примечание: В строке символов нет символа новой строки

ожидаемый результат из приведенного выше фрагмента:

"example example example" соответствует строке 1 и "example example" соответствует строке 2.

Что вы имеете в виду под "вырезать" текст? Как выглядит ваш ожидаемый результат?

Ricky Mo 10.04.2019 06:43

Попробуйте свойство переноса текста css. Нет необходимости в javascript

Mayank Dudakiya 10.04.2019 06:46

@RickyMo Верно, как и выше, например, div занимает более 2 строк. Я хочу просто получить текст в строке выше

Tuan Jihoo 10.04.2019 06:49

@MayankDudakiya Мне нужно получить текст в строке выше, а не скрывать нижнюю строку

Tuan Jihoo 10.04.2019 06:52

Вы имеете в виду, что у вас есть что-то вроде jsfiddle.net/c0tz35xv и вы пытаетесь получить каждый визуализированная линия (["This is", "some", "quite long" ...)?

Kaiido 10.04.2019 06:54

@Кайидо, верно, это моя идея

Tuan Jihoo 10.04.2019 06:59

Я не знаю, возможно ли это, но с какой целью вы это делаете? Возможно, есть лучшие способы решить вашу настоящую проблему.

Ricky Mo 10.04.2019 06:59

Один из способов — использование CSS, как я упоминал ниже. Другой способ — использовать JavaScript для усечения текста до заданного предела.

Razana N. 10.04.2019 07:22
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
5
8
1 404
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Попробуйте CSS

div {
  width:200px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

Они хотят получить содержимое визуализированного текста после того, как CSS применяет разрывы строк, они не хотят знать, как их делать.

Kaiido 10.04.2019 07:24

Это можно сделать с помощью CSS. Javascript не требуется.

<div> example example example example example</div>
<style>
div{
    width: 200px;
    word-wrap: break-word;
}
</style>

Они хотят получить содержимое визуализированного текста после того, как CSS применяет разрывы строк, они не хотят знать, как их делать.

Kaiido 10.04.2019 07:25
Ответ принят как подходящий

Вы можете использовать Диапазон API и его удобный метод getBoundingClientRect(), чтобы определить, какой символ отмечает захват в TextNode.

Обратите внимание, что это, очевидно, необходимо пересчитывать каждый раз, когда размер окна изменяется / что-то меняет макет.

function getLineBreaks(node) {
  // we only deal with TextNodes
  if (!node || !node.parentNode || node.nodeType !== 3)
    return [];
  // our Range object form which we'll get the characters positions
  const range = document.createRange();
  // here we'll store all our lines
  const lines = [];
  // begin at the first char
  range.setStart(node, 0);
  // initial position
  let prevBottom = range.getBoundingClientRect().bottom;
  let str = node.textContent;
  let current = 1; // we already got index 0
  let lastFound = 0;
  let bottom = 0;
  // iterate over all characters
  while(current <= str.length) {
    // move our cursor
    range.setStart(node, current);
    if (current < str.length -1)
     range.setEnd(node, current+1);
    bottom = range.getBoundingClientRect().bottom;
    if (bottom > prevBottom) { // line break
      lines.push(
        str.substr(lastFound , current - lastFound) // text content
      );
      prevBottom = bottom;
      lastFound = current;
    }
    current++;
  }
  // push the last line
  lines.push(str.substr(lastFound));

  return lines;
}

console.info(getLineBreaks(document.querySelector('.test').childNodes[0]));
div.test {
  width: 50px;
  margin-bottom: 100px;
  word-break: break-all;
}

body>.as-console-wrapper{max-height:100px}
<div class = "test">This is some quite long content that will wrap in multiple lines</div>

И если вам нужна относительная y позиция каждой строки:

function getLineBreaks(node) {
  // we only deal with TextNodes
  if (!node || !node.parentNode || node.nodeType !== 3)
    return [];
  // our Range object form which we'll get the characters positions
  const range = document.createRange();
  // here we'll store all our lines
  const lines = [];
  // begin at the first character
  range.setStart(node, 0);
  // get the position of the parent node so we can have relative positions later
  let contTop = node.parentNode.getBoundingClientRect().top;
  // initial position
  let prevBottom = range.getBoundingClientRect().bottom;
  let str = node.textContent;
  let current = 1; // we already got index 0
  let lastFound = 0;
  let bottom = 0;
  // iterate over all characters
  while(current <= str.length) {
    // move our cursor
    range.setStart(node, current);
    if (current < str.length - 1)
      range.setEnd(node, current+1); // wrap it (for Chrome...)
    bottom = range.getBoundingClientRect().bottom;
    if (bottom > prevBottom) { // line break
      lines.push({
        y: prevBottom - (contTop || 0), // relative bottom
        text: str.substr(lastFound , current - lastFound) // text content
      });
      prevBottom = bottom;
      lastFound = current;
    }
    current++;
  }
  // push the last line
  lines.push({
    y: bottom - (contTop || 0),
    text: str.substr(lastFound)
  });

  return lines;
}

console.info(getLineBreaks(document.querySelector('.test').childNodes[0]));
div.test {
  width: 50px;
  margin-bottom: 100px;
}

body>.as-console-wrapper{max-height:100px}
<div class = "test">This is some quite long content that will wrap in multiple lines</div>

Для тех, кому нужно работать с элементами, а не с одним текстовым узлом, вот переписывание который вполне может потерпеть неудачу (например, с направлением RTL), но это должно подойти для большинства случаев.

function getLineBreaks(elem) {
  // our Range object form which we'll get the characters positions
  const range = document.createRange();
  // here we'll store all our lines
  const lines = [];
  const nodes = grabTextNodes(elem);
  let left = 0;
  // get the position of the parent node so we can have relative positions later
  let contTop = nodes[0].parentNode.getBoundingClientRect().top;
  // initial position
  let prevLeft = null;
  let lineText = "";
  let startRange = null;
  for (const node of nodes) {
    let nodeText = node.textContent;
    const textLength = nodeText.length;
    let rangeIndex = 0;
    let textIndex = 0;
    while (rangeIndex <= textLength) {
      range.setStart(node, rangeIndex);
      if (rangeIndex < textLength - 1) {
        range.setEnd(node, rangeIndex + 1); // wrap the range (for Chrome...)
      }
      left = range.getBoundingClientRect().right;
      if (prevLeft === null) { // first pass
        prevLeft = left;
        startRange = range.cloneRange();
      }
      else if (left < prevLeft) { // line break
        // store the current line content
        lineText += nodeText.slice(0, textIndex);
                startRange.setEnd(range.endContainer, range.endOffset);
        const { bottom } = startRange.getBoundingClientRect();
        lines.push({
                    y: bottom - contTop,
          text: lineText
        });
        // start a new line
        prevLeft = left;
        lineText = "";
        nodeText = nodeText.slice(textIndex);
        textIndex = 0;
        startRange = range.cloneRange();
      }
      rangeIndex++;
      textIndex++;
      prevLeft = left;
    }
    // add the remaining text from this node into the current line content
    lineText += nodeText;
  }
  // push the last line
    startRange.setEnd(range.endContainer, range.endOffset);
  const { bottom } = startRange.getBoundingClientRect();
  lines.push({
    y: bottom - contTop,
    text: lineText
  });
  return lines;
}

console.info(getLineBreaks(document.querySelector('.test')));

function grabTextNodes(elem) {
  const walker = document.createTreeWalker(elem, NodeFilter.SHOW_TEXT, null);
  const nodes = [];
  while (walker.nextNode()) {
    nodes.push(walker.currentNode);
  }
  return nodes;
}
div.test {
  width: 150px;
  margin-bottom: 100px;
}
.red { color: red; }
<div class = "test"><span class = "red">This</span> is some quite long content that will wrap in <span class = "red">mutiple</span> lines..</div>

спасибо за код. но в скрипке это не работает, когда я меняю класс .red css, чтобы также иметь размер шрифта: 2em

icube 10.01.2022 19:47

@icube, да, использование .bottom в этом случае было не очень разумным, элементы .red не имеют одинакового значения .bottom, поскольку они больше. Я обновил свой ответ, включив вместо него новую версию, которая смотрит на .left, но обратите внимание, что это все еще не является пуленепробиваемым. О, и если вы хотите это как скрипку: jsfiddle.net/puk067ym

Kaiido 11.01.2022 04:28

Другие вопросы по теме