在没有 innerHTML 的情况下更改 JavaScript 中的 HTML

Posted

技术标签:

【中文标题】在没有 innerHTML 的情况下更改 JavaScript 中的 HTML【英文标题】:Changing HTML in JavaScript without innerHTML 【发布时间】:2019-04-17 21:17:51 【问题描述】:

假设我的代码非常简单,如下所示:

let content = "";

for(let i=0; i<array.length; i++)
    content+='<h1>array[i]</h1>';


document.getElementById('some_id').innerhtml = content;

我不喜欢将 HTML 放入我的 javascript 代码的想法,但我不知道在不使用 innerHTML、JQuery 的 html() 方法或简单地创建新 DOM 的情况下将元素插入 DOM 的任何其他方法以编程方式添加元素。

在业界或最佳实践中,从 JavaScript 插入 HTML 元素的最佳方式是什么?

提前致谢!

【问题讨论】:

您可以使用document.createElementnodeYouWishToExtend.appendChild(nodeYouCreated)。对于另一种方法,您可以查看 React、Angular、Vue、Knockout 等框架。 最佳实践是创建 DOM 元素对象并将文本插入到这些元素中以防范 XSS ps 你的预感认为在 javascript 中编写 html 是“糟糕的”,这在很大程度上是正确的。我不知道array 来自哪里,但假设用户可以更改它,他们可能会潜入一些“不安全”的值。例如&lt;script type="text/javascript"&gt;doBadThing()&lt;/script&gt;。除非你要转义你的输入,或者使用一个库,否则你不应该直接使用用户来源的输入来设置 innerHTML。 content+='&lt;h1&gt;array[i]&lt;/h1&gt;'; 不会评估 array[i] 而是将其打印为文本。 【参考方案1】:

您可以使用 DOMParser 和 ES6 字符串文字:

const template = text => (
`
<div class="myClass">
    <h1>$text</h1>
</div>
`);

您可以在内存中创建一个片段:

const fragment = document.createDocumentFragment();
const parser = new DOMParser();
const newNode = parser.parseFromString(template('Hello'), 'text/html');
const els = newNode.documentElement.querySelectorAll('div');
for (let index = 0; index < els.length; index++) 
  fragment.appendChild(els[index]);  

parent.appendChild(fragment);

由于文档片段在内存中而不是主 DOM 树的一部分,因此将子片段附加到它不会导致页面重排(计算元素的位置和几何形状)。从历史上看,使用文档片段可能会带来更好的性能。

来源:https://developer.mozilla.org/en-US/docs/Web/API/Document/createDocumentFragment

基本上你可以使用任何你想要的模板,因为它只是一个返回一个字符串的函数,你可以将它输入到解析器中。

希望对你有帮助

【讨论】:

【参考方案2】:

你可以使用createElement()方法

在 HTML 文档中,document.createElement() 方法创建由 tagName 指定的 HTML 元素,如果无法识别 tagName,则创建 HTMLUnknownElement。

这是一个例子,

document.body.onload = addElement;

function addElement ()  
  // create a new div element 
  var newDiv = document.createElement("div"); 
  // and give it some content 
  var newContent = document.createTextNode("Hi there and greetings!"); 
  // add the text node to the newly created div
  newDiv.appendChild(newContent);  

  // add the newly created element and its content into the DOM 
  var currentDiv = document.getElementById("div1"); 
  document.body.insertBefore(newDiv, currentDiv); 
<!DOCTYPE html>
<html>
<head>
  <title>||Working with elements||</title>
</head>
<body>
  <div id="div1">The text above has been created dynamically.</div>
</body>
</html>

【讨论】:

【参考方案3】:

一种使用 JavaScript 的 insertAdjacentHTML 方法插入 HTML 元素的灵活且更快速(高效)的方法。它允许您准确指定放置元素的位置。可能的位置值是:

'beforebegin' 'afterbegin' 'beforeend' 'afterend'

像这样:

 document.getElementById("some_id").insertAdjacentElement("afterbegin", content);

Here's a Fiddle example

【讨论】:

【参考方案4】:

以编程方式而不是通过 HTML 创建元素应该具有预期的效果。

const parent = document.getElementById('some_id');
// clear the parent (borrowed from https://***.com/questions/3955229/remove-all-child-elements-of-a-dom-node-in-javascript)

while (parent.firstChild) 
    parent.removeChild(parent.firstChild);


// loop through array and create new elements programmatically
for(let i=0; i<array.length; i++)
    const newElem = document.createElement('h1');
    newElem.innerText = array[i];
    parentElement.appendChild(newElem);

【讨论】:

如果你有很多节点,我发现使用 while 循环清除子节点会更慢,我一直喜欢这个 el.parentNode.replaceChild(el.cloneNode(false), el ) 使用 false 标志克隆元素,该标志会生成没有任何子元素的副本,然后将元素替换为更精简的 self。 我确实认为它看起来更慢,但这是否处理孩子不存在的情况?

以上是关于在没有 innerHTML 的情况下更改 JavaScript 中的 HTML的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript:如何在没有 innerHTML 的情况下替换元素内的代码

如何在没有 innerHTML = ""; 的情况下清除 div 的内容

在不更改 `src=` 的情况下重新加载 iFrame(同域)

在没有 jQuery 的情况下绑定 HTML 内容 [重复]

在不使用函数的情况下显示带有 innerHTML 的对象?

在没有管理员权限的情况下更改 Windows 10 中的 Java_Home 路径