Альтернатива jQuery text(), которая включает пробелы между элементами?

У меня есть некоторый произвольный текст тела в контейнере. Я не контролирую его, поэтому не знаю его структуры. Но что-то вроде этого:

<div id='content-area'>
  <h1>Heading</h1>
  <p>A paragraph or two</p>
  <ul>
    <li>item 1</li>
    <li>item 2</li>
  </ul>
</div>

Это простой пример для иллюстрации, на самом деле он может содержать гораздо больше элементов и вложенных элементов, таких как таблицы.

Я хочу вытащить весь текст и сделать некоторую обработку на словах. Я использую следующий jQuery для получения текста.

$('#content-area').text()
// HeadingA paragraph or twoitem 1item 2

Проблема в том, что между каждым помеченным элементом нет пробелов. В документации говорится:

Из-за различий в парсерах HTML в разных браузерах возвращаемый текст может меняться в новых и других пробелах.

И все мои поиски, похоже, подтягивают результаты для удаления пробелов. Есть ли способ вытащить весь текст и сохранить пространство между элементами? Нужно происходить в браузере, поэтому методы javascript-ish.

Ответ 1

В случае неизвестной вложенной структуры вы можете добавлять пробелы к каждому элементу

https://jsfiddle.net/3y2yLexv/1/

$( "*" ).each(function( index ) {
   $( this ).append(' ');
});

var str = $('#content-area').text();
//Of course you have to trim duplicated blank spaces.
str = str.replace(/\s\s+/g, ' ');
$('#new').text(str);

Ответ 2

Я думаю, что jQuery использует свойство textContent, которое может форматировать вашу строку. Вместо этого вы можете пересечь дерево, которое ищет текстовые_Nodes и добавляет его в String/Array.

Например:

function getText(domElement) {
  var root = domElement;
  var text = [];

  function traverseTree(root) {
    Array.prototype.forEach.call(root.childNodes, function(child) {
      if (child.nodeType === 3) {
        var str = child.nodeValue.trim();
        if (str.length > 0) {
          text.push(str);
        }
      } else {
        traverseTree(child);
      }
    });
  }
  traverseTree(root);
  return text.join(' ');
}

var text = getText(document.getElementById('content-area'));
document.getElementById('results').innerHTML = text;
<div id='content-area'>
  <h1>Heading</h1>
  <p>A paragraph or two</p>
  <ul>
    <li>item 1</li>
    <li>item 2</li>
  </ul>
</div>
<pre id="results"></pre>

Ответ 3

Вы можете использовать jQuery для each метода для сбора элементов и включать интервал с использованием конкатенации строк.

Что-то в этом роде для грубого примера:

$(function(){
    var output = "";
    $( "li" ).each( function( index, element ){
        output += $(this).text() + " ";
    });
    $('#output').html(output);
});

Не стесняйтесь видеть вывод, отображаемый путем кэширования того, что вы хотите, в переменную, которая заставит его записывать только DOM один раз.

http://jsfiddle.net/bq50s8eb/

РЕДАКТИРОВАТЬ:

Если вы не знаете, что такое структура, но вы уверены, что все они будут в пределах одного div, вы можете использовать универсальный селектор jQuery.

$(function(){
    var output = "";
    $( "#content-area *" ).each( function( index, element ){
        output += $(this).text() + " ";
    });
    $('#output').html(output);
});

http://jsfiddle.net/bq50s8eb/1/

Ответ 4

Я не уверен, что это работает в любом случае. Мое решение будет регулярным выражением, которое фильтрует теги, пробелы и новые строки из raw html:

$("#content-area").html().replace(/([\s\n]*<[^>]*>[\s\n]*)+/g," ")

http://jsfiddle.net/limond/mrnctqcv/1/

EDIT: Конечно, это работает только в том случае, если вы можете избежать любых тегов, содержащих html, которые пользователь не может видеть (например, <script>...</script>)

Ответ 5

Я решил это, добавив пробел: до css. При динамическом добавлении элемента с помощью jquery вы можете сделать это так:

$('<a/>') 
.attr("style", 'white-space:pre;')
.text('    X    ');