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

IT技术 javascript html
2021-02-06 07:53:57

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

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

<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 点 - 11 点)周四练习@ 5 楼(晚上 8 点 - 11 点)周日练习@(晚上 9 点 - 12 点)

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

6个回答

最简单的解决方案是使用以下 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()or 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 轻松解决的问题,这变得相当复杂。

所以问题是我能够看到文本区域中的空格,但是当我在 API 端收到它们并将它们发送到电子邮件时,它不会保留空格。
2021-03-23 07:53:57
多谢,伙计。你让我今天一整天都感觉很好
2021-03-25 07:53:57
white-space: pre-line 对我有用,因为 pre-wrap 在第一行有缩进。
2021-03-28 07:53:57
这似乎是最全面的答案。为什么会被否决?如果它包含不正确的信息,请分享。
2021-03-29 07:53:57
@ApurvaKunkulol:这听起来像是服务器端代码中的问题。您可以提出一个关于它的新问题,但您需要提供一个最小的可重现示例来演示该问题。
2021-04-09 07:53:57

目标容器应具有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-wrap或者pre-line会更好。pre防止换行,因此很长的文本行将强制水平滚动条。
2021-03-16 07:53:57
@IsmaelMiguel:这很奇怪——我是从 IE 11 发布的,它在这里工作得很好。显然IEtextContent从版本 9 开始就支持了
2021-03-19 07:53:57
此代码容易受到 HTML 注入的影响,因为您将未转义的用户输入分配给innerHTML. 在这种情况下,只需替换innerHTMLwith即可textContent解决。
2021-04-03 07:53:57
@IlmariKaronen 那会破坏事情。您需要设置innerText textContent仅设置 textContent在 IE(任何版本)中innerText不起作用,仅设置将来可能不适用于 Chrome,也不适用于 Firefox。
2021-04-03 07:53:57
@IlmariKaronen 这很奇怪......我不知道这一点。但是,innerText如果您需要 IE8,最好将其包含在内
2021-04-05 07:53:57

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您可以appendChild使用document.createTextNode(text)and 代替使用document.createElement('br')
2021-03-15 07:53:57
提高效率的一个好方法是document.createDocumentFragment.
2021-03-18 07:53:57
@IlmariKaronen,科斯,这不是关于安全性或效率的问题。不过我确实优化了它。
2021-04-03 07:53:57
@misher:OP 要求保留换行符的方法,而不是保留换行符允许 HTML 注入的方法。当您请求帮助修复 UI 错误时获得一个免费的安全漏洞有点像当您要求一个汉堡包时在肉饼中获得一个免费的图钉。无论如何,由于您的“优化”代码似乎不再容易受到攻击,因此我删除了我的反对票。
2021-04-11 07:53:57

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

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

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

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

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