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

Posted

技术标签:

【中文标题】从文本区域获取文本时如何保留换行符?【英文标题】:How do I preserve line breaks when getting text from a textarea? 【发布时间】:2017-03-17 23:36:36 【问题描述】:

当用户点击提交时,我在文本区域中获取值。然后我把这个值放在页面的其他地方。但是,当我这样做时,它会丢失换行符,使输出非常难看。

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

<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 点 - 晚上 11 点)

星期四练习 @ 5 楼(晚上 8 点 - 晚上 11 点)

周日练习@(晚上 9 点 - 凌晨 12 点)

输出是:

小组日程:周二练习@5楼(8 pm - 11 pm)周四练习@5th(8 pm - 11 pm)周日练习@(9 pm - 12 am)

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

【问题讨论】:

如果您被允许使用 jQuery,这可能会对您有所帮助:copy-from-textarea-to-div-preserving-linebreaks 或者这可能会有所帮助 preserve-line-breaks-in-textarea-input 实际上保留了换行符,目标元素只是设置为在显示文本时忽略它们,但如果你检查它,你会看到它们在这里。 Stefano 的回答只是将目标设置为不再忽略它们,这可能是最好的方法。 抱歉吹毛求疵,倒数第二行的 getElementById 函数在哪里?我假设您在其他地方定义了它,或者您忘记了document 【参考方案1】:

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

white-space: pre-wrap;

This property 导致匹配元素中的空格和换行符以与&lt;textarea&gt; 相同的方式处理。也就是说,连续的空格不会折叠,并且在显式换行处换行(但如果超出元素的宽度,也会自动换行)。

鉴于到目前为止发布的几个答案都容易受到html injection 的攻击(例如,因为他们将未转义的用户输入分配给innerHTML)或其他错误,让我举一个例子来说明如何安全和正确地做到这一点,基于您的原始代码:

document.getElementById('post-button').addEventListener('click', function () 
  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);
);
#card-stack p 
  background: #ddd;
  white-space: pre-wrap;  /* <-- THIS PRESERVES THE LINE BREAKS */

textarea 
  width: 100%;
<textarea id="post-text" class="form-control" rows="8" 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>
<input type="button" id="post-button" value="Post!">
<div id="card-stack"></div>

请注意,与您的原始代码一样,上面的 sn-p 使用 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

这里的 sn-p 与上面相同,但没有使用 append()prepend()

document.getElementById('post-button').addEventListener('click', function () 
  var post = document.createElement('p');
  var postText = document.getElementById('post-text').value;
  post.textContent = postText;
  var card = document.createElement('div');
  card.appendChild(post);
  var cardStack = document.getElementById('card-stack');
  cardStack.insertBefore(card, cardStack.firstChild);
);
#card-stack p 
  background: #ddd;
  white-space: pre-wrap;  /* <-- THIS PRESERVES THE LINE BREAKS */

textarea 
  width: 100%;
<textarea id="post-text" class="form-control" rows="8" 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>
<input type="button" id="post-button" value="Post!">
<div id="card-stack"></div>

附言。如果您真的想不使用 使用 CSS white-space 属性,另一种解决方案是用&lt;br&gt; HTML 标记显式替换文本中的任何换行符。棘手的部分是,为了避免引入细微的错误和潜在的安全漏洞,您必须首先在 before 文本中转义任何 HTML 元字符(至少 &amp;&lt;)这个替换。

可能最简单和最安全的方法是让浏览器为您处理 HTML 转义,如下所示:

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

document.getElementById('post-button').addEventListener('click', function () 
  var post = document.createElement('p');
  var postText = document.getElementById('post-text').value;
  post.textContent = postText;
  post.innerHTML = post.innerHTML.replace(/\n/g, '<br>\n');  // <-- THIS FIXES THE LINE BREAKS
  var card = document.createElement('div');
  card.appendChild(post);
  var cardStack = document.getElementById('card-stack');
  cardStack.insertBefore(card, cardStack.firstChild);
);
#card-stack p 
  background: #ddd;

textarea 
  width: 100%;
<textarea id="post-text" class="form-control" rows="8" 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>
<input type="button" id="post-button" value="Post!">
<div id="card-stack"></div>

请注意,虽然这将修复换行符,但它不会阻止 HTML 渲染器折叠连续的空格。可以(在某种程度上)通过用不间断空格替换文本中的一些空格来模拟这一点,但老实说,对于可以用一行 CSS 轻松解决的问题来说,这变得相当复杂。

【讨论】:

这似乎是最全面的答案。为什么它被否决了?如果其中包含不正确的信息,请分享。 white-space: pre-line 对我有用,因为 pre-wrap 在第一行有缩进。 谢谢老兄。你成就了我的一天 所以问题是我能够看到文本区域中的空格,但是当我在 API 端收到它们并将它们发送到电子邮件中时,它不会保留空格. @ApurvaKunkulol:这听起来像是您的服务器端代码中的一个问题。您可以提出一个新问题,但您需要提供一个 minimal reproducible example 来证明该问题。【参考方案2】:

目标容器应具有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>

【讨论】:

pre-wrappre-line 会更好。 pre 防止换行,因此很长的文本行将强制水平滚动条。 此代码易受 HTML 注入攻击,因为您将未转义的用户输入分配给 innerHTML。在这种情况下,只需将 innerHTML 替换为 textContent 即可解决此问题。 @IlmariKaronen 这会破坏一切。您需要设置innerText textContent。仅设置 textContent 将无法在 IE(任何版本)中使用,仅设置 innerText 将来可能无法在 Chrome 上使用,也无法在 Firefox 上使用。 @IsmaelMiguel:这很奇怪——我是从 IE 11 发布的,它在这里工作得很好。 Apparently IE 从版本 9 开始支持 textContent @IlmariKaronen 这很奇怪......我没有意识到这一点。但如果您需要 IE8,最好包含 innerText【参考方案3】:

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标签……

【讨论】:

@IlmariKaronen 所说的:此代码不正确,因为您将纯文本 (textarea.value) 分配给需要 HTML (innerHTML) 的属性。这是一种类型错误,会导致从损坏的文本到安全漏洞的各种问题。除了使用innerHTML,您还可以使用appendChilddocument.createTextNode(text)document.createElement('br') 提高效率的好方法是document.createDocumentFragment @IlmariKaronen, Kos,这不是关于安全性或效率的问题。不过,我确实对其进行了优化。 @misher:OP 要求提供一种保留换行符的方法,而不是一种保留换行符的方法允许 HTML 注入。当您寻求帮助以修复 UI 错误时获得一个免费的安全漏洞有点像当您要求一个汉堡包时获得一个免费的图钉。无论如何,由于您的“优化”代码似乎不再容易受到攻击,我已经删除了我的反对票。【参考方案4】:

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

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

此 HTML 值将保留换行符。希望这会有所帮助。

【讨论】:

这也将产生未转义的用户输入和 HTML 标记的混合,如果生成的 html 字符串实际上被呈现为 HTML,则会产生 HTML 注入漏洞。 @IlmariKaronen - 所以你担心有人可能会攻击自己? OP 没有提到任何类型的数据库。一个用户的输入将如何以任何方式影响另一个用户?也许这仅适用于 OP 的眼睛并且对卫生的需求为零(如果它甚至根本不需要它的话)。 @Jesse:一般来说,很难确定用户输入来自受信任的来源。即使攻击者无法直接将文本注入文本区域,也有大量社交媒体病毒通过社交工程说服天真的用户将某些内容复制粘贴到易受攻击的输入字段中而传播开来。此外,即使输入确实可以 100% 信任,此代码仍然会破坏任何包含 HTML 元字符(如 &amp;&lt;)的文本。即使安全不是问题,这仍然是一个错误。 @IlmariKaronen - 我一点也不担心攻击,但感谢您提供这些信息!【参考方案5】:

您可以使用 Javascript 设置 width 的 div 并将 white-space:pre-wrap 添加到 p tag,这会破坏每行末尾的 textarea 内容。

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>

【讨论】:

【参考方案6】:

我想您不希望您的 textarea-content 被解析为 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>

【讨论】:

【参考方案7】:

类似的问题在这里

detect line breaks in a text area input

detect line break in textarea

你可以试试这个:

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, '&lt;br/&gt;') 会在内容中找到源代码/\n/g 中的所有换行符,并将其替换为html 换行符&lt;br/&gt;


另一种选择是使用 html &lt;pre&gt; 标记。 请看下面的演示

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>

【讨论】:

请重新阅读问题。发帖人询问如何在将文本区域中的文本放在页面上而不是另一个文本区域内时保留换行符。 您的第一个示例有问题,无法正常工作。 (您甚至从未将 textContent.replace() 的结果分配给任何东西。)您的第二个示例容易受到与其他几个答案相同的 HTML 注入错误的影响,因为您将未转义的用户输入分配给 innerHTML (您的第一个示例是同样容易受到攻击,如果您尝试对 replace() 调用的输出实际做任何有用的事情)。 谢谢! Outlook 2013 实际上知道
 是什么

以上是关于从文本区域获取文本时如何保留换行符?的主要内容,如果未能解决你的问题,请参考以下文章

HTML5如何从文本区域中获取选定的文本

Angular 8过滤器:保留文本区域输入的换行符

发送邮件时保留文本区域的换行符

使用 Ruby on Rails 在文本区域中保留换行符

在用户提交的内容中呈现换行符(Python Web 应用程序)

如何用换行符回显文本区域的输入?