最简单的解决方案是使用以下 CSS 属性简单地设置要插入文本的元素的样式:
white-space: pre-wrap;
此属性导致匹配元素中的空格和换行符以与 a 中相同的方式处理<textarea>。也就是说,连续的空格不会折叠,并且在显式换行符处断行(但如果它们超过元素的宽度也会自动换行)。
鉴于到目前为止发布的几个答案都容易受到HTML 注入(例如,因为他们将未转义的用户输入分配给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>
 
 
请注意,与您的原始代码一样,上面的代码片段使用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():
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>
 
 
附言。如果您真的想在不使用 CSSwhite-space属性的情况下执行此操作,另一种解决方案是使用<br>HTML 标记显式替换文本中的任何换行符。棘手的部分是,为了避免引入微妙的错误和潜在的安全漏洞,您必须在执行此替换之前首先转义文本中的任何 HTML 元字符(至少,&和<)。
可能最简单和最安全的方法是让浏览器为您处理 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 轻松解决的问题,这变得相当复杂。