Wie behalte ich Zeilenumbrüche bei, wenn Text aus einem Textbereich abgerufen wird?

95

Ich erhalte den Wert in einem Textbereich, wenn der Benutzer auf "Senden" klickt. Ich nehme dann diesen Wert und platziere ihn an einer anderen Stelle auf der Seite. Wenn ich dies tue, verliert es jedoch Zeilenumbrüche, was die Ausgabe ziemlich hässlich macht.

Hier ist der Textbereich, auf den ich zugreife:

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

Hier ist der JavaScript-Code, der auf den Beitrag zugreift und ihn transkribiert.

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

Wenn die Eingabe so etwas wie:

Gruppenplan:

Dienstag Training im 5. Stock (20 - 23 Uhr)

Donnerstag Training im 5. Stock (20 - 23 Uhr)

Sonntagsübung @ (21 - 12 Uhr)

Die Ausgabe ist:

Gruppenplan: Dienstag Training im 5. Stock (20 - 23 Uhr) Donnerstag Training im 5. Stock (20 - 23 Uhr) Sonntag Training im (21 - 12 Uhr)

Gibt es also eine Möglichkeit, Zeilenumbrüche beizubehalten?

Ethan Vander Horn
quelle
1
Wenn Sie jQuery verwenden dürfen, kann dies hilfreich sein: Kopieren von Textbereichen nach Div-Erhalt von Zeilenumbrüchen Alternativ kann dies dazu beitragen, Zeilenumbrüche in Textbereichseingaben beizubehalten
Kevin Kloet
1
Zeilenumbrüche bleiben tatsächlich erhalten. Das Zielelement ist so eingestellt, dass sie beim Anzeigen des Texts ignoriert werden. Wenn Sie ihn jedoch überprüfen, werden Sie sehen, dass sie hier sind. Stefanos Antwort setzt das Ziel einfach so, dass es sie nicht länger ignoriert, wahrscheinlich der beste Weg.
Spektren
2
Tut mir leid, aber woher kommt die getElementByIdFunktion in der vorletzten Zeile? Ich gehe davon aus, dass Sie es entweder anderswo definiert haben oder das vergessen haben document.
Trysis

Antworten:

175

Die einfachste Lösung besteht darin, das Element, in das Sie den Text einfügen, einfach mit der folgenden CSS-Eigenschaft zu formatieren:

white-space: pre-wrap;

Diese Eigenschaft bewirkt, dass Leerzeichen und Zeilenumbrüche in den übereinstimmenden Elementen genauso behandelt werden wie in a <textarea>. Das heißt, aufeinanderfolgende Leerzeichen werden nicht reduziert, und Zeilen werden bei expliziten Zeilenumbrüchen unterbrochen (aber auch automatisch umbrochen, wenn sie die Breite des Elements überschreiten).

Angesichts der Tatsache, dass einige der hier veröffentlichten Antworten bisher anfällig für HTML-Injection waren (z. B. weil sie uneingeschränkte Benutzereingaben zuweisen innerHTML) oder auf andere Weise fehlerhaft sind, möchte ich anhand Ihres Originalcodes ein Beispiel dafür geben, wie dies sicher und korrekt durchgeführt werden kann:


Beachten Sie, dass das obige Snippet wie Ihr Originalcode append()und verwendet prepend(). Zum jetzigen Zeitpunkt gelten diese Funktionen noch als experimentell und werden nicht von allen Browsern vollständig unterstützt. Wenn Sie sicher sein und mit älteren Browsern kompatibel bleiben möchten, können Sie diese ganz einfach wie folgt ersetzen:

  • element.append(otherElement)kann ersetzt werden durch element.appendChild(otherElement);
  • element.prepend(otherElement)kann ersetzt werden durch element.insertBefore(otherElement, element.firstChild);
  • element.append(stringOfText)kann ersetzt werden durch element.appendChild(document.createTextNode(stringOfText));
  • element.prepend(stringOfText)kann ersetzt werden durch element.insertBefore(document.createTextNode(stringOfText), element.firstChild);
  • als Sonderfall, wenn elementleer ist, beides element.append(stringOfText)und element.prepend(stringOfText)kann einfach durch ersetzt werden element.textContent = stringOfText.

Hier ist das gleiche Snippet wie oben, jedoch ohne Verwendung von append()oder prepend():


Ps. Wenn Sie dies wirklich ohne Verwendung der CSS- white-spaceEigenschaft tun möchten , besteht eine alternative Lösung darin, alle Zeilenumbrüche im Text explizit durch <br>HTML-Tags zu ersetzen . Der schwierige Teil ist, dass Sie, um subtile Fehler und potenzielle Sicherheitslücken zu vermeiden, zuerst alle HTML-Metazeichen (mindestens &und <) im Text umgehen müssen, bevor Sie diese Ersetzung durchführen.

Der wahrscheinlich einfachste und sicherste Weg, dies zu tun, besteht darin, den Browser das HTML-Escape für Sie wie folgt handhaben zu lassen:

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

Beachten Sie, dass dies zwar die Zeilenumbrüche behebt, jedoch nicht verhindert, dass aufeinanderfolgende Leerzeichen vom HTML-Renderer reduziert werden. Es ist möglich, dies zu emulieren, indem ein Teil des Leerzeichens im Text durch nicht unterbrechende Leerzeichen ersetzt wird. Ehrlich gesagt wird dies jedoch für etwas, das mit einer einzigen CSS-Zeile trivial gelöst werden kann, ziemlich kompliziert.

Ilmari Karonen
quelle
2
Dies scheint die umfassendste Antwort zu sein. Warum wird es abgelehnt? Wenn es falsche Informationen enthält, teilen Sie diese bitte mit.
Ethan Vander Horn
4
Leerraum: Pre-Line funktionierte für mich, da Pre-Wrap Einrückungen in der ersten Zeile hatte.
Dev4life
1
Danke Alter. Du hast meinen Tag gemacht
Thatman
Die Sache ist also, dass ich die Leerzeichen im Textbereich sehen kann, aber wenn ich sie auf der API-Seite erhalte und sie in eine E-Mail gesendet werden, bleiben die Leerzeichen nicht erhalten.
Apurva Kunkulol
@ApurvaKunkulol: Das klingt nach einem Problem in Ihrem serverseitigen Code. Sie könnten eine neue Frage dazu stellen, aber Sie müssten ein minimal reproduzierbares Beispiel bereitstellen , das das Problem demonstriert.
Ilmari Karonen
23

Der Zielcontainer sollte den white-space:preStil haben. Versuchen Sie es unten.

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

Stefano Altieri
quelle
10
pre-wrapoder pre-linewäre besser. preVerhindert das Umbrechen von Zeilen, sodass eine sehr lange Textzeile die horizontale Bildlaufleiste erzwingt.
Salman A
10
Dieser Code ist anfällig für HTML-Injection, da Sie uneingeschränkte Benutzereingaben zuweisen innerHTML. In diesem Fall würde ein einfaches Ersetzen innerHTMLdurch textContentdas Problem behoben.
Ilmari Karonen
1
@IlmariKaronen Das wird die Dinge kaputt machen. Sie müssen eingestellt innerText und textContent . Nur Einstellungen textContentfunktionieren in IE (jeder Version) nicht und Einstellungen innerTextfunktionieren möglicherweise in Zukunft nicht mehr in Chrome und nicht in Firefox.
Ismael Miguel
3
@IsmaelMiguel: Das ist seltsam - ich poste dies aus IE 11 und es funktioniert hier einwandfrei. Anscheinend unterstützt IE textContentseit Version 9.
Ilmari Karonen
2
@IlmariKaronen Das ist seltsam ... das war mir nicht bewusst. Es ist jedoch eine gute Idee, diese einzuschließen, innerTextwenn Sie IE8 benötigen.
Ismael Miguel
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>

Sie können Textbereichszeilen in Arrays aufteilen:

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

Verwenden Sie es dann, um möglicherweise mehr p-Tags zu generieren ...

Kolodi
quelle
3
Was @IlmariKaronen gesagt hat: Dieser Code ist falsch, weil Sie textarea.valueeiner Eigenschaft, die HTML ( innerHTML) erwartet , Klartext ( ) zuweisen . Dies ist ein Typfehler, der Probleme verursacht, die von fehlerhaftem Text bis zu Sicherheitslücken reichen. Anstatt zu verwenden innerHTML, können Sie appendChildmit document.createTextNode(text)und tun document.createElement('br').
Kos
1
Ein guter Weg, dies effizienter zu gestalten, ist document.createDocumentFragment.
Kos
1
@IlmariKaronen, Kos, dies war weder eine Frage der Sicherheit noch der Effizienz. Ich habe es jedoch optimiert.
Kolodi
3
@misher: Das OP hat nach einer Möglichkeit gefragt, Zeilenumbrüche beizubehalten, nicht nach einer Möglichkeit, Zeilenumbrüche beizubehalten und HTML-Injection zuzulassen. Wenn Sie um Hilfe bitten, um einen UI-Fehler zu beheben, erhalten Sie eine kostenlose Sicherheitslücke, wenn Sie nach einem Hamburger fragen. Wie auch immer, da Ihr "optimierter" Code nicht mehr anfällig zu sein scheint, habe ich meine Ablehnung entfernt.
Ilmari Karonen
3

Hier ist eine Idee, da Sie möglicherweise mehrere Zeilenumbrüche in einem Textfeld haben:

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

Dieser HTML-Wert behält den Zeilenumbruch bei. Hoffe das hilft.

reza
quelle
1
Dies führt auch zu einer Mischung aus nicht entkoppelten Benutzereingaben und HTML-Tags, wodurch eine Sicherheitsanfälligkeit bezüglich HTML-Injection entsteht, wenn die resultierende htmlZeichenfolge jemals tatsächlich als HTML gerendert wird.
Ilmari Karonen
@IlmariKaronen - Sie haben also Bedenken, dass sich jemand selbst angreifen könnte? Das OP erwähnt keine Art von Datenbank. Wie würde sich die Eingabe eines Benutzers in irgendeiner Weise auf einen anderen Benutzer auswirken? Vielleicht ist dies etwas, das nur für die Augen der OP bestimmt ist und keinen Bedarf an sanitären Einrichtungen hat (wenn es überhaupt einen Bedarf dafür gibt).
Jesse
1
@ Jesse: Im Allgemeinen ist es schwierig sicherzustellen, dass Benutzereingaben von einer vertrauenswürdigen Quelle stammen. Auch wenn es für einen Angreifer nicht möglich ist, Text direkt in den Textbereich einzufügen, haben sich zahlreiche Social-Media-Viren verbreitet, indem naive Benutzer über Social Engineering davon überzeugt wurden, etwas in ein anfälliges Eingabefeld zu kopieren und einzufügen. Selbst wenn der Eingabe wirklich zu 100% vertraut werden kann, entstellt dieser Code dennoch jeden Text, der HTML-Metazeichen wie &oder enthält <. Auch wenn Sicherheit kein Problem darstellt, ist dies dennoch ein Fehler.
Ilmari Karonen
@IlmariKaronen - Ich bin überhaupt nicht besorgt über einen Angriff, aber danke für diese Information!
Ethan Vander Horn
3

Sie könnten Set widthvon div mit Javascript und fügen Sie white-space:pre-wrapzu p tag, diese Pause Ihren TextArea- Inhalt am Ende jeder Zeile.

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>

frnt
quelle
3

Ich nehme an, Sie möchten nicht, dass Ihr Textbereich-Inhalt als HTML analysiert wird. In diesem Fall können Sie es einfach als Klartext festlegen, damit der Browser es nicht als HTML behandelt und keine Zeilenumbrüche entfernt. Kein CSS oder Vorverarbeitung erforderlich.

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

tkausl
quelle
2

Ähnliche Fragen gibt es hier

Erkennen von Zeilenumbrüchen in einer Textbereichseingabe

Zeilenumbruch im Textbereich erkennen

Sie können dies versuchen:

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/>')Ruft den Textinhalt des Textbereichs ab und findet das gesamte Zeilenumbruchzeichen im Quellcode /\n/gim Inhalt und ersetzt es durch den HTML-Zeilenumbruch <br/>.


Eine andere Option ist die Verwendung des HTML- <pre> Tags. Siehe die Demo unten

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>

Abk
quelle
2
Bitte lesen Sie die Frage erneut. Das Poster fragt, wie Zeilenumbrüche beibehalten werden sollen, wenn Text aus einem Textbereich auf eine Seite und nicht in einen anderen Textbereich eingefügt wird.
Jesse
1
Ihr erstes Beispiel ist fehlerhaft und funktioniert nicht. (Sie weisen niemals das Ergebnis von textContent.replace()irgendetwas zu.) Ihr zweites Beispiel ist anfällig für denselben HTML-Injection-Fehler wie mehrere andere Antworten, da Sie uneingeschränkte Benutzereingaben zuweisen innerHTML(und Ihr erstes Beispiel wäre gleichermaßen anfällig, wenn Sie es versuchen würden um tatsächlich etwas Nützliches mit der Ausgabe des replace()Anrufs zu tun ).
Ilmari Karonen
Vielen Dank! Outlook 2013 weiß tatsächlich, was <pre> ist
user1566694