从文本区域获取文本时如何保留换行符?


98

当用户点击提交时,我正在textarea中获取值。然后,我将这个值放在页面上的其他位置。但是,当我这样做时,它会丢失换行符,从而使输出变得难看。

这是我正在访问的文本区域:

<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楼(8 pm-11 pm)

周四练习@ 5楼(8 pm-11 pm)

周日练习@(9 pm-12 am)

输出为:

小组时间表:周二练习@ 5楼(晚上8点至晚上11点)周四练习@ 5楼(晚上8点至晚上11点)周日练习@(晚9点至上午12点)

那么有没有办法保留换行符?


1
如果您被允许使用jQuery,这可能会帮助您:从textarea复制到div保留换行符或者这可能有助于在textarea输入中
Kevin Kloet

1
换行符实际上是保留的,目标元素只是设置为在显示文本时忽略它们,但是如果您检查它,就会看到它们在这里。Stefano的答案只是将目标设置为不再忽略它们,这可能是最好的选择。
频谱

2
抱歉,nitpick,但是getElementById从倒数第二行开始的功能在哪里?我假设您在其他地方定义了它,或者您忘记了document
trysis

Answers:


186

最简单的解决方案是使用以下CSS属性简单地设置要插入文本的元素的样式:

white-space: pre-wrap;

此属性导致匹配元素内的空白和换行符与内的处理方式相同<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()


附言 如果您确实想在使用CSSwhite-space属性的情况下执行此操作,则另一种解决方案是用<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
多谢,伙计。你决定了我的一天
Thatman

因此,我可以在文本区域中看到空格,但是当我在API端收到空格并将其发送到电子邮件中时,它不会保留空格。
Apurva Kunkulol

@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-wrappre-line会更好。pre防止换行,因此很长的文本行将强制水平滚动条。
Salman A

10
此代码容易受到HTML注入的影响,因为您要将未转义的用户输入分配给innerHTML。在这种情况下,只需更换innerHTMLtextContent将修复它。
Ilmari Karonen

1
@IlmariKaronen那会破坏一切。您需要设置innerText textContent。设置仅 textContent在IE(任何版本)中不起作用,并且仅innerText将来可能在Chrome上不起作用,并且在Firefox上不起作用。
Ismael Miguel

3
@IsmaelMiguel:太奇怪了-我是从IE 11发布的,在这里工作正常。显然IE浏览器已经支持textContent自9版
ILMARI Karonen

2
@IlmariKaronen真是奇怪……我没有意识到。但是,innerText如果需要IE8 ,最好包括在内。
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>

您可以将textarea行拆分为数组:

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,Kos,这不是关于安全性或效率的问题。不过,我确实对其进行了优化。
kolodi '16

3
@misher:OP要求保留换行符的方法,而不是保留换行符允许HTML注入的方法。当您寻求帮助来修复UI错误时获得免费的安全漏洞,就像在请求汉堡包时在小馅饼中获得免费的图钉。无论如何,由于您的“优化”代码似乎不再容易受到攻击,因此我删除了我的反对意见。
Ilmari Karonen

4

这是一个想法,因为您可能在文本框中包含多个换行符:

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

此HTML值将保留换行符。希望这可以帮助。


1
这还将产生未转义的用户输入和HTML标记的混合,如果生成的html字符串实际以HTML形式呈现,则将创建HTML注入漏洞。
Ilmari Karonen

@IlmariKaronen-所以您担心的是有人可能会攻击自己?OP没有提及任何类型的数据库。一个用户的输入将如何以任何方式影响另一用户?也许这仅是OP的眼睛,对卫生的需求为零(如果甚至根本不需要)。
杰西

1
@Jesse:通常,很难确定用户输入来自受信任的来源。即使没有办法让攻击者直接将文本注入文本区域,也已经通过通过社会工程说服幼稚的用户将某些内容复制粘贴到易受攻击的输入字段中而传播了许多社交媒体病毒。此外,即使输入确实是100%可以信任的,此代码仍会破坏包含HTML元字符(如&或)的任何文本<。即使安全性不是问题,但这仍然是一个错误。
Ilmari Karonen '16

@IlmariKaronen-我根本不担心遭受攻击,但是感谢您提供此信息!
伊桑·范德·霍恩

3

您可以width使用Javascript设置div并将其添加white-space:pre-wrapp 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

我想您不希望将textarea内容解析为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;将获取textarea的文本内容,并将在内容textContent.replace(/\n/g, '<br/>')的源代码/\n/g中找到所有换行符,并将其替换为html line-break <br/>


另一种选择是使用html <pre>标签。请参阅下面的演示

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()调用的输出做任何有用的事情)。
Ilmari Karonen

谢谢!Outlook 2013实际上知道<pre>是什么
user1566694
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.