使用Javascript编写HTML的正确方式是什么?

75

看起来有经验的Web开发人员在编写动态HTML时使用JavaScript中的document.write()不太好。

为什么呢?正确的方法是什么?


6
JQuery。它可以正确地处理DOM操作,同时让您编写像这样简单的代码:$("<div><span>文本</span><div>子元素</div></div>").appendTo('body'); - John Fisher
2
这是一个情况,jQuery的梗实际上很有道理。 "我看到你正在尝试使用JavaScript编写HTML。 你应该完全放弃它并使用jQuery!" - Adam Bellaire
4
jQuery绝不是使用JavaScript创建HTML的“正确”方式。它是用JavaScript编写的,并将使用下面答案中的一个或多个方法,但作为通用库的缺点是它不会像开发人员一样为每种情况做出明智的策略选择。 - Tim Down
1
@Tim:这种方法并不比其他任何给出的方法更“正确”或“错误”,但它是一个完全有效的方法。在所有情况下都没有一个“正确”的答案。你所提到的“缺点”只是一种特征:当潜在的好处微不足道时,我可能不会花时间分析HTML生产的最佳策略。根据你的选择,透明地管理这种复杂性可能是一个优势或劣势。人们可以决定使用jQuery,直到需要更优化的策略为止。 - Adam Bellaire
1
@亚当 - 讲得很有道理。“缺点”在编写最高效代码方面仍然是准确的,但我认同你的观点,即效率增益并不总是重要到足以抵消jQuery方法的方便之处,但前提是页面上已经在使用jQuery处理其他非琐碎任务。这绝对不是一个值得单独使用jQuery来完成的工作。 - Tim Down
12个回答

63

document.write()只能在页面最初解析和创建DOM时使用。一旦浏览器到达关闭的</body>标签并且DOM准备就绪,就不能再使用document.write()了。

我不会说使用document.write()是正确或不正确的,这取决于您的情况。在某些情况下,您只需要使用document.write()来完成任务。看看Google分析如何注入到大多数网站中。

在DOM准备就绪后,您有两种方法插入动态HTML(假设我们将插入新的HTML到<div id="node-id"></div>):

  1. 在节点上使用innerHTML:

  2. var node = document.getElementById('node-id');
    node.innerHTML('<p>some dynamic html</p>');
    
    使用 DOM 方法:
    var node = document.getElementById('node-id');
    var newNode = document.createElement('p');
    newNode.appendChild(document.createTextNode('some dynamic html'));
    node.appendChild(newNode);
    
    使用DOM API方法可能是最纯粹的方法,但已被证明innerHTML要快得多,并在JavaScript库(如jQuery)中作为底层使用。
    注意:为了使其起作用,<script>必须放在<body>标签内部。

1
你能提供innerHTML始终更快的证据吗?我怀疑这并不总是正确的。如果您将节点逐个添加到DOM中现有的节点中,则我预计innerHTML会更快,因为浏览器可能需要在每个阶段操纵和重新渲染文档的部分,但如果您创建一个新的节点树并在最后将其根节点添加到DOM中,则我预计这将与使用innerHTML一样快或更快。 - Tim Down
1
@Maiku - 哈哈,确实如此 :)@Tim - 这里有一个基准测试 http://www.quirksmode.org/dom/innerhtml.html而且,使用文档片段似乎是最快的:http://ejohn.org/blog/dom-documentfragments/ - Ricky
7
node.innerHTML = '<p>some dynamic html</p>'; 在 Android 上的 WebView 上 innerHTML 不是一个函数。 - domen
Firefox不支持innerHTML和outerHTML。 - Lennon
变量node = document.getElementById('node-id'); node.innerHTML('<p>一些动态的HTML</p>'); 这对我不起作用, 我使用document.getElementById("node-id").innerHTML = "<p>一些动态的HTML</p>";(火狐) - Firebirdz
显示剩余7条评论

28

document.write() 在 XHTML 中无法使用。它在页面完成加载后被执行,只能输出一系列 HTML 字符串。

由于 HTML 的实际内存表示是 DOM,直接操作 DOM 是更新页面的最佳方式。

实现此目的的方法是以编程方式创建节点,然后将它们附加到 DOM 中的现有位置。例如,假设我有一个具有“header”ID属性的 div 元素,则可以通过以下方式引入一些动态文本:

// create my text
var sHeader = document.createTextNode('Hello world!');

// create an element for the text and append it
var spanHeader = document.createElement('span');
spanHeader.appendChild(sHeader);

// grab a reference to the div header
var divHeader = document.getElementById('header');

// append the new element to the header
divHeader.appendChild(spanHeader);

4
当你调用它时,它实际上会被执行。如果在页面加载后调用它,它将覆盖内容。 - Maiku Mori
2
еқҡжҢҒдҪҝз”ЁHTMLе’Ңdocument.writeд»Қ然жҳҜдёҖдёӘжңүз”Ёзҡ„е·Ҙе…·гҖӮ - Tim Down

10
  1. 根据Tom所述的DOM方法。

  2. 如iHunger所提到的innerHTML。

相对于字符串设置属性和内容而言,DOM方法更为可取。如果你发现自己写了 innerHTML= '<a href="'+path+'">'+text+'</a>',实际上就是在客户端创建了新的跨站脚本安全漏洞,如果你花费了时间来保护服务器端就有些可惜了。

传统上说,与innerHTML相比,DOM方法被描述为“缓慢”的。但这并不是整个故事的全部。缓慢的是插入大量子节点:

 for (var i= 0; i<1000; i++)
     div.parentNode.insertBefore(document.createElement('div'), div);

这会导致DOM在其节点列表中查找正确插入元素的位置,移动其他子节点,插入新节点,更新指针等等,工作量很大。

另一方面,设置现有属性的值或文本节点的数据非常快速;您只需更改一个字符串指针,就完成了操作。这比使用innerHTML序列化父节点,然后进行更改并解析回来要快得多(而且不会丢失不可序列化的数据,如事件处理程序、JS引用和表单值)。

有一些技巧可以在不使用childNodes遍历的情况下进行DOM操作。特别是要注意cloneNode和使用DocumentFragment的可能性。但是有时innerHTML确实更快。您仍然可以兼顾两个世界,使用innerHTML编写具有属性值和文本内容占位符的基本结构,然后使用DOM稍后填充它们。这样可以避免编写自己的escapehtml()函数以解决上述转义/安全问题。


9
也许在这种情况下使用jQuery是一个好主意。它提供了方便的功能,您可以做像这样的事情:
$('div').html('<b>Test</b>');

请查看http://docs.jquery.com/Attributes/html#val以了解更多信息。

4
因为人们正在谈论更优雅、更快速和跨浏览器的做事方式,而不得不加载jQuery来实现这一点,这并不是一个答案。 - Lennon

4
你可以改变页面上元素的innerHTMLouterHTML

2
最好使用innerHTML,因为outerHTML的支持不太广泛。 - bobince

3

element.InnerHtml = allmycontent: 这会重写元素内的所有内容。您必须使用变量 let allmycontent="this is what I want to print inside this element" 来存储您想要放置在此元素内的整个内容。如果不这样做,每次调用此函数时,您的元素内容都将被擦除并替换为上一次调用它时的内容。

document.write(): 可以多次使用,每次都会在页面上调用时打印内容。

但要注意:document.write() 方法适用于在页面创建时插入内容。因此,在有大量数据需要编写时,例如产品或图像目录,请勿重复使用。

以下是一个简单的示例:您的侧边栏菜单中的所有 li 都存储在一个名为 "tab" 的数组中,您可以直接在 HTML 页面中使用脚本标记创建 JS 脚本,然后在迭代函数中使用 write 方法来插入这些 li 到页面中。

<script type="text/javascript">
document.write("<ul>");
for (var i=0; i<=tab.length; i++){
    document.write(tab[i]);
    }document.write("</ul>");
</script>`

这是因为Js在加载时以线性方式进行解释,所以请确保您的脚本位于html页面的正确位置。您也可以使用外部Js文件,但同样需要在要解释的地方声明它。
因此,document.write不能用于响应"用户交互"(如单击或悬停)而写入页面内容,因为DOM已经创建,写入方法将像上面所说的那样写入新页面(清除实际执行堆栈并开始新堆栈和新DOM树)。在这种情况下,请使用:
element.innerHTML=("Myfullcontent");

要了解更多关于文档方法的内容:打开您的控制台:document; 然后打开:__proto__: HTMLDocumentPrototype

您会在文档对象中看到函数属性"write"。 您还可以使用document.writeln,它会在每个语句后添加一个新行。 要了解有关函数/方法的更多信息,请将其名称写入控制台,不带括号:document.write; 控制台将返回描述而不是调用它。


3

我不是特别擅长JavaScript或其最佳实践,但document.write()以及innerHtml()基本上允许您编写字符串,这些字符串可能是有效的HTML,也可能无效;它只是字符。通过使用DOM,您可以确保符合标准的HTML,这将通过明显的错误HTML使您的页面不会崩溃。

而且,正如Tom所提到的,JavaScript在页面加载后执行;最好的做法可能是通过标准HTML(通过.html文件或服务器所做的任何操作[i.e. php])完成页面的初始设置。


1
如果您使用JavaScript编写动态组件,则最终将使用JavaScript编写到DOM中。虽然document.write()并不是正确的方法,但在大多数情况下,您可能会使用innerHTML。由于在所有浏览器中使用innerHTML比使用createNode/appendChild要快得多。当您必须生成大量html/DOM元素时,这非常重要。还有,应该是document而不是documment ;) - Maiku Mori

1

使用JavaScript编写HTML有很多种方法。

当您想要在页面实际加载之前写入页面时,document.write仅在此时有用。如果您在页面加载后(在onload事件中)使用document.write(),它将创建新页面并覆盖旧内容。此外,它不适用于XML,包括XHTML。

另一方面,其他方法不能在DOM创建之前(页面加载)使用,因为它们直接与DOM一起工作。

这些方法包括:

  • node.innerHTML = "Whatever";
  • document.createElement('div'); 和 node.appendChild()等。

在大多数情况下,node.innerHTML更好,因为它比DOM函数更快。大多数情况下,它还可以使代码更易读和更小。


1

最好的方法无疑是尽量避免在JavaScript中进行任何繁重的HTML 创建。从服务器发送下来的标记应该包含大部分内容,您可以使用CSS进行操作,而不是强制删除/替换元素(如果可能的话)。

如果您正在模拟小部件系统等“聪明”的操作,则不适用此方法。


0

document.write方法非常有限。您只能在页面加载完成之前使用它。您不能使用它来更新已加载页面的内容。

您可能想要的是innerHTML


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接