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)"]
这将为访问该页面的每个其他用户触发警报。现在我们有一个问题。更聪明的用户会将 display: none 放在该 img 样式上,并使其将当前用户的 cookie 发布到跨域站点。恭喜,您的所有用户登录详细信息现在都已在 Internet 上公开。
因此,要理解的重要一点是,使用 innerHTML 并没有错,如果您只是使用它来构建模板,并且仅使用您自己受信任的开发人员代码,那么它是完美的。真正的问题应该是“如何将具有换行符的不受信任的用户文本附加到我的 HTML 文档中”。
这就提出了一个问题:我们对换行使用哪种策略?我们是否使用 [br] 元素?[p]s 还是 [div]s?
这是一个解决问题的简短函数:
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);
}
}
}
你基本上可以把它扔到你的 common_functions.js 文件中的某个地方,然后只要你需要附加任何用户/api/etc -> 不受信任的文本(即不是你自己的开发团队编写的)到你的 html 页面。
用法示例:
insertUntrustedText(document.querySelector('.myTextParent'), 'line1\nline2\r\nline3', 'br');
参数 newlineStrategy 只接受有效的 dom 元素标签,所以如果你想要 [br] 换行符,传递 'br',如果你想要 [p] 元素中的每一行,传递 'p' 等。