nelek的回答是目前为止最好的,但它依赖于设置css值:white-space: pre,这可能不是理想的。
我想提供一个不同的解决方案,试图解决应该在这里提出的真正问题:
“如何将不受信任的文本插入DOM元素?”
如果您信任文本,为什么不只使用innerHTML?
domElement.innerHTML = trustedText.replace(/\r/g, '').replace(/\n/g, '<br>');
应该对所有合理情况都足够。
如果你决定使用.textContent而不是.innerHTML,那么这意味着你不信任即将插入的文本,对吗?这是一个合理的担忧。
例如,你有一个表单,用户可以创建一个帖子,在发布后,帖子文本被存储在你的数据库中,并在其他用户访问相关页面时附加到页面上。
如果你在这里使用innerHTML,你将面临安全漏洞。也就是说,用户可以发布像这样的内容:
<script>alert(1);</script>
如果你使用innerHTML,它不会触发警报,但它应该让你明白为什么使用innerHTML可能会有问题。一个更聪明的用户会发布
<img src="invalid_src" onerror="alert(1)" />
这将会触发每个访问该页面的其他用户的警报。现在我们有一个问题。更聪明的用户会在那个img样式上放置display: none,并使其将当前用户的cookie发布到跨域站点。恭喜,你所有用户的登录详细信息现在都暴露在互联网上。
因此,重要的是要理解,使用innerHTML并没有错,如果你只是使用它来构建模板,只使用自己信任的开发人员代码,那么它就是完美的。真正的问题应该是“如何将具有换行符的不受信任的用户文本附加到我的HTML文档中”。
This raises a question: which strategy do we use for newlines? do we use
elements?
s or s?
Here is a short function that solves the problem:
function insertUntrustedText(domElement, untrustedText, newlineStrategy) {
domElement.innerHTML = '';
var lines = untrustedText.replace(/\r/g, '').split('\n');
var linesLength = lines.length;
if(newlineStrategy === 'br') {
for(var i = 0; i < linesLength; i++) {
domElement.appendChild(document.createTextNode(lines[i]));
domElement.appendChild(document.createElement('br'));
}
}
else {
for(var i = 0; i < linesLength; i++) {
var lineElement = document.createElement(newlineStrategy);
lineElement.textContent = lines[i];
domElement.appendChild(lineElement);
}
}
}
You can basically throw this somewhere in your common_functions.js file and then just fire and forget whenever you need to append any user/api/etc -> untrusted text (i.e. not-written-by-your-own-developer-team) to your html pages.
usage example:
insertUntrustedText(document.querySelector('.myTextParent'), 'line1\nline2\r\nline3', 'br');
the parameter newlineStrategy accepts only valid dom element tags, so if you want [br] newlines, pass 'br', if you want each line in a [p] element, pass 'p', etc.