Як зберегти розриви рядків при отриманні тексту з текстового поля?


96

Я отримую значення в текстовій області, коли користувач натискає надіслати. Потім я приймаю це значення і розміщую його деінде на сторінці. Однак, коли я це роблю, він втрачає символи нового рядка, що робить результат досить потворним.

Ось текстове поле, до якого я отримую доступ:

<textarea id="post-text" class="form-control" rows="3" placeholder="What's up?" required></textarea>

Ось код JavaScript, який здійснює доступ до публікації та її транскрипцію.

var post = document.createElement('p');
var postText = document.getElementById('post-text').value;
post.append(postText);
var card = document.createElement('div');
card.append(post);
var cardStack = document.getElementById('#card-stack');
cardStack.prepend(card);

Коли вводиться щось на зразок:

Розклад груп:

Тренінг у вівторок @ 5 поверх (20:00 - 23:00)

Тренінг у четвер на 5 поверсі (20:00 - 23:00)

Недільна практика @ (21:00 - 12:00)

Результат:

Груповий графік: тренування вівторка на 5 поверсі (20:00 - 23:00) Тренінг у четвер на 5 поверсі (20:00 - 23:00) Тренування в неділю @ (21:00 - 12:00)

То чи є спосіб зберегти розриви рядків?


1
якщо вам дозволено використовувати jQuery, це може вам допомогти: copy-from-textarea-to-div-saserving-linebreaks, або це може допомогти зберегти-line-break-in-textarea-input
Кевін Клоет,

1
Розриви рядків насправді зберігаються, цільовий елемент просто налаштований ігнорувати їх під час відображення тексту, але якщо ви перевірите його, ви побачите, що вони тут. Відповідь Стефано просто встановлює ціль більше не ігнорувати їх, мабуть, найкращий шлях.
спектри

2
Вибачте за nitpick, але звідки getElementByIdфункція з 2-го до останнього рядка? Я припускаю, що ви визначили це в іншому місці, або ви забули document.
триз

Відповіді:


177

Найпростішим рішенням є просто стиль елемента, до якого ви вставляєте текст, за допомогою наступної властивості CSS:

white-space: pre-wrap;

Ця властивість призводить до того, що пробіли та нові рядки в відповідних елементах обробляються так само, як і всередині a <textarea>. Тобто, послідовний пробіл не згортається, а рядки ламаються за явними новими рядками (але вони також обертаються автоматично, якщо вони перевищують ширину елемента).

Враховуючи, що кілька відповідей, розміщених тут до цього часу, були вразливими до введення HTML (наприклад, тому, що вони призначають невмінне введення користувачем innerHTML) або іншим способом помилки, дозвольте мені навести приклад того, як це зробити безпечно та правильно, виходячи з вашого вихідного коду:


Зверніть увагу, що, як і ваш оригінальний код, наведений вище фрагмент використовує append()та prepend(). На момент написання статті ці функції досі вважаються експериментальними та не повністю підтримуються усіма браузерами. Якщо ви хочете бути в безпеці та залишатися сумісними зі старими браузерами, ви можете досить легко замінити їх наступним чином:

  • element.append(otherElement)можна замінити на element.appendChild(otherElement);
  • element.prepend(otherElement)можна замінити на element.insertBefore(otherElement, element.firstChild);
  • element.append(stringOfText)можна замінити на element.appendChild(document.createTextNode(stringOfText));
  • element.prepend(stringOfText)можна замінити на element.insertBefore(document.createTextNode(stringOfText), element.firstChild);
  • як особливий випадок, якщо elementпорожній, обидва element.append(stringOfText)і element.prepend(stringOfText)можна просто замінити на element.textContent = stringOfText.

Ось той самий фрагмент, що і вище, але без використання append()або prepend():


Ps. Якщо ви дійсно хочете зробити це без використання white-spaceвластивості CSS , альтернативним рішенням буде явна заміна будь-яких символів нового рядка в тексті <br>тегами HTML. Хитра частина полягає в тому, що, щоб уникнути непомітних помилок та потенційних дірок у безпеці, вам слід спочатку уникнути будь-яких метасимволів HTML (як мінімум, &і <) у тексті, перш ніж робити цю заміну.

Напевно, найпростіший і найбезпечніший спосіб зробити це - дозволити браузеру обробляти HTML-екран, що працює за вас, наприклад:

var post = document.createElement('p');
post.textContent = postText;
post.innerHTML = post.innerHTML.replace(/\n/g, '<br>\n');

Зауважте, що, хоча це виправить розриви рядків, це не завадить послідовному пробілу згортати візуатор HTML. Можна (начебто) наслідувати це, замінюючи частину пробілів у тексті нерозривними пробілами, але, чесно кажучи, це стає досить складним для того, що можна тривіально вирішити одним рядком CSS.


2
Це, здається, найбільш вичерпна відповідь. Чому за нього проголосували? Якщо вона містить неправильну інформацію, будь ласка, поділіться.
Ітан Вандер Горн,

4
пробіл: попередній рядок працював для мене, оскільки попереднє обгортання мало відступ на першому рядку.
dev4life

1
Дякую, чувак. Ви зробили мій день
чоловіком

Справа в тому, що я бачу пробіли в текстовій області, але коли я отримую їх у кінці API і вони надсилаються на електронну пошту, це не зберігає пробіли.
Апурва Кункулол

@ApurvaKunkulol: Це звучить як проблема у коді на стороні сервера. Ви можете задати нове запитання щодо цього, але вам потрібно надати мінімальний відтворюваний приклад, який демонструє проблему.
Ilmari Karonen

23

Цільовий контейнер повинен мати white-space:preстиль. Спробуйте нижче.

<script>
function copycontent(){
 var content = document.getElementById('ta').value;
 document.getElementById('target').innerText = content;
}
</script>
<textarea id='ta' rows='3'>
  line 1
  line 2
  line 3
</textarea>
<button id='btn' onclick='copycontent();'>
Copy
</button>
<p id='target' style='white-space:pre'>

</p>


10
pre-wrapабо pre-lineбуло б краще. preзапобігає переносу рядків, тому дуже довгий рядок тексту змусить горизонтальну смугу прокрутки.
Salman A

10
Цей код вразливий до введення HTML, оскільки ви призначаєте невміщений ввід користувача innerHTML. У цьому випадку виправити це може просто заміна innerHTMLна textContent.
Ілмарі Каронен

1
@IlmariKaronen Це зламає ситуацію. Вам потрібно встановити innerText і textContent . Тільки налаштування textContentне працюватиме в IE (будь-яка версія), і лише налаштування innerTextможуть не працювати в Chrome у майбутньому і не працюватимуть у Firefox.
Ісмаель Мігель

3
@IsmaelMiguel: Це дивно - я публікую це в IE 11, і тут це чудово працює. Очевидно IE підтримує textContentз версії 9.
Ілмарі Каронен

2
@IlmariKaronen Це дивно ... Я цього не знав. Але корисно включити, innerTextякщо вам потрібен IE8.
Ісмаель Мігель

7

function get() {
  var arrayOfRows = document.getElementById("ta").value.split("\n");
  var docfrag = document.createDocumentFragment();
  
  var p = document.getElementById("result");
  while (p.firstChild) {
    p.removeChild(p.firstChild);
  }
  
  arrayOfRows.forEach(function(row, index, array) {
    var span = document.createElement("span");
    span.textContent = row;
    docfrag.appendChild(span);
    if(index < array.length - 1) {
      docfrag.appendChild(document.createElement("br"));
    }
  });

  p.appendChild(docfrag);
}
<textarea id="ta" rows=3></textarea><br>
<button onclick="get()">get</button>
<p id="result"></p>

Ви можете розділити рядки тексту на масив:

var arrayOfRows = postText.value.split("\n");

Потім використовуйте його для створення, можливо, більше тегів p ...


3
Що сказав @IlmariKaronen: цей код неправильний, оскільки ви призначаєте відкритий текст ( textarea.value) властивості, яка очікує HTML ( innerHTML). Це помилка типу, яка спричиняє проблеми - від розбитого тексту до дір в безпеці. Замість того, щоб використовувати innerHTML, ви можете робити за appendChildдопомогою document.createTextNode(text)і document.createElement('br').
Кос,

1
Хороший спосіб зробити це більш ефективним document.createDocumentFragment.
Кос,

1
@IlmariKaronen, Кос, це не було питання ні про безпеку, ні про ефективність. Однак я його оптимізував.
колоді

3
@misher: ОП запитував про спосіб збереження розривів рядків, а не про спосіб збереження розривів рядків та дозволу введення HTML. Отримати безкоштовну діру в безпеці, коли ви звертаєтесь за допомогою, щоб виправити помилку в користувацькому інтерфейсі, це як би отримати безкоштовну мініатюру в котлеті, коли ви просите гамбургер. У будь-якому випадку, оскільки ваш "оптимізований" код здається вже не вразливим, я видалив свій голос проти.
Ілмарі Каронен

3

Ось ідея, оскільки у вас у текстовому полі може бути кілька нових рядків:

 var text=document.getElementById('post-text').value.split('\n');
 var html = text.join('<br />');

Це значення HTML збереже новий рядок. Сподіваюся, це допомагає.


1
Це також призведе до поєднання введеного користувачем вхідного тегу та тегів HTML, що створить уразливість введення HTML, якщо отриманий htmlрядок коли-небудь фактично відображатиметься як HTML.
Ілмарі Каронен

@IlmariKaronen - Тож у вас є заклопотаність тим, що хтось може напасти на себе? В OP не згадується про будь-який тип бази даних. Як введення даних одного користувача може вплинути на іншого користувача будь-яким чином? Можливо, це те, що призначене лише для очей операційної системи та має 0 потреб у санітарії (якщо вона взагалі в цьому потребує).
Джессі

1
@Jesse: Загалом, важко бути впевненим, що дані користувача надходять із надійного джерела. Навіть якщо зловмисник не може безпосередньо вводити текст у текстове поле, існує безліч вірусів соціальних мереж, які поширюються, переконуючи наївних користувачів за допомогою соціальної інженерії скопіювати щось у вразливе поле введення. Крім того, навіть якщо вводу дійсно можна довіряти на 100%, цей код все одно обробляє будь-який текст, що містить метасимволи HTML, такі як &або <. Навіть якщо безпека не є проблемою, це все одно помилка.
Ilmari Karonen

@IlmariKaronen - Мене зовсім не турбує напад, але дякую за цю інформацію!
Ітан Вандер Горн,

3

Ви можете встановити widthdiv за допомогою Javascript і додати, white-space:pre-wrapщоб p tagце розбило вміст тексту в кінці кожного рядка.

document.querySelector("button").onclick = function gt(){
var card = document.createElement('div');
card.style.width = "160px";
card.style.background = "#eee";
var post = document.createElement('p');
var postText = document.getElementById('post-text').value;
post.style.whiteSpace = "pre-wrap";
card.append(post);
post.append(postText);
document.body.append(card);
}
<textarea id="post-text" class="form-control" rows="3" placeholder="What's up?" required>
Group Schedule:

Tuesday practice @ 5th floor (8pm - 11 pm)

Thursday practice @ 5th floor (8pm - 11 pm)

Sunday practice @ (9pm - 12 am)</textarea>
<br><br>
<button>Copy!!</button>


3

Припускаю, ви не хочете, щоб ваш текстовий вміст аналізувався як HTML. У цьому випадку ви можете просто встановити його як відкритий текст, щоб браузер не обробляв його як HTML і не видаляв нові рядки. CSS та попередня обробка не потрібні.

<script>
function copycontent(){
 var content = document.getElementById('ta').value;
 document.getElementById('target').innerText = content;
}
</script>
<textarea id='ta' rows='3'>
  line 1
  line 2
  line 3
</textarea>
<button id='btn' onclick='copycontent();'>
Copy
</button>
<p id='target'></p>


2

Подібні запитання тут

виявити розриви рядків у текстовій області введення

виявити розрив рядка в текстовому полі -

Ви можете спробувати це:

var submit = document.getElementById('submit');

submit.addEventListener('click', function(){
var textContent = document.querySelector('textarea').value;
  
document.getElementById('output').innerHTML = textContent.replace(/\n/g, '<br/>');
  

});
<textarea cols=30 rows=10 >This is some text
this is another text

Another text again and again</textarea>
<input type='submit' id='submit'>


<p id='output'></p>

document.querySelector('textarea').value;отримає текстовий вміст текстової області та textContent.replace(/\n/g, '<br/>')знайде весь символ нового рядка у вихідному коді /\n/gвмісту та замінить його на розрив рядка html <br/>.


Інший варіант - використовувати <pre> тег html . Див. Демо нижче

var submit = document.getElementById('submit');

submit.addEventListener('click', function(){

  var content = '<pre>';
  
  var textContent = document.querySelector('textarea').value;
  
  content += textContent;
  
  content += '</pre>';

  document.getElementById('output').innerHTML = content;

});
<textarea cols=30 rows=10>This is some text
this is another text

Another text again and again </textarea>
<input type='submit' id='submit'>

<div id='output'> </div>


2
Будь ласка, перечитайте питання ще раз. Плакат запитує, як зберегти розриви рядків, розміщуючи текст із текстового поля на сторінці, а не всередині іншого текстового поля.
Джессі

1
Ваш перший приклад - баггі і не працює. (Ви навіть ніколи не призначаєте результат textContent.replace()ні до чого.) Ваш другий приклад є вразливим до тієї самої помилки ін'єкції HTML, що і кілька інших відповідей, оскільки ви призначаєте нескопійований ввід користувача innerHTML(і ваш перший приклад буде однаково вразливим, якщо ви спробуєте щоб зробити щось корисне з результатом replace()виклику).
Ілмарі Каронен

Дякую! Outlook 2013 насправді знає, що таке <pre>
user1566694
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.