在教程中,我学会了使用document.write。 现在,我了解到很多人对此表示反对。 我已经尝试过print(),但是它确实将其发送到打印机。
那么我应该使用哪些替代方法,为什么不使用document.write? w3schools和MDN都使用document.write。
-
print()解析为window.print()。
-
在xhtml + xml页面中替换document.write()的可能重复项
-
JavaScripts print()与PHPs print()不同。 JS从字面上将页面发送到打印机,而PHP仅输出代码。
替换HTML的原因是由于JavaScript函数document.write()邪恶。
它绝对是"错误的形式"。仅当您在页面加载时使用它时,它才适用于网页。如果在运行时使用它,它将用输入替换整个文档。而且,如果您将其应用为严格的XHTML结构,那么它甚至不是有效的代码。
问题:
document.write writes to the document stream. Calling document.write on a closed (or loaded) document automatically calls document.open which will clear the document.
-来自MDN的报价
document.write()有两个伙伴,document.open()和document.close()。加载HTML文档时,该文档为"打开"状态。文档加载完成后,文档已"关闭"。此时使用document.write()将会删除整个(关闭的)HTML文档,并将其替换为新的(打开的)文档。这意味着您的网页已擦除自身,并开始从头开始编写新页面。
我相信document.write()也会导致浏览器的性能下降(如果我错了,请纠正我)。
一个例子:
此示例在页面加载后将输出写入HTML文档。当您按下" exterminate"按钮时,观看document.write()的邪恶力量会清除整个文档:
1 2
| I am an ordinary HTML page. I am innocent, and purely for informational purposes. Please do not <input type="button" onclick="document.write('This HTML page has been succesfully exterminated.')" value="exterminate"/>
me! |
替代方案:
-
.innerHTML这是一个很好的选择,但是必须将此属性附加到要放置文本的元素上。
示例:document.getElementById('output1').innerHTML = 'Some text!';
-
.createTextNode()是W3C推荐的替代方法。
示例:var para = document.createElement('p');
para.appendChild(document.createTextNode('Hello, '));
注意:已知这会导致某些性能下降(比.innerHTML慢)。我建议改用.innerHTML。
.innerHTML替代示例:
1 2 3 4 5 6 7
| I am an ordinary HTML page.
I am innocent, and purely for informational purposes.
Please do not
<input type="button" onclick="document.getElementById('output1').innerHTML = 'There was an error exterminating this page. Please replace <wyn>.innerHTML</wyn> with <wyn>document.write()</wyn> to complete extermination.';" value="exterminate"/>
me!
<p id="output1">
</p> |
-
那么,邪恶只是在文档关闭后才开始吗?除了不流行之外,在此之前使用document.write是否还有其他缺点?关闭文档的时间是否存在实际不确定性?
-
@ BobStein-VisiBone,是的,可以在页面加载期间调用document.write(),而浏览器正在解析页面。解析/加载页面后,调用此函数还将调用document.open(),这将擦除页面并从头开始。我想不出任何理由在页面加载期间不使用该功能,除了与您在其他时间向页面添加内容的方式保持一致之外。浏览器完成文档解析后,文档将立即关闭。
-
document.write()似乎仍然是CDN本地回退的最佳解决方案。我还没有尝试过getElementById / innerHTML,但是一个createElement / insertBefore解决方案却是不同步的。
-
@ Godisgood,document.write不会出现性能问题,因为它与浏览器加载初始HTTP响应时使用的功能完全相同。
-
@Pacerier是的,但是我的意思是页面加载后使用document.write()的速度较慢,因为它必须清除文档,然后在每次调用该函数时重新打开它。 .innerHTML不会执行任何操作,因此我很确定我读到它毕竟更快。我将寻找一个来源来支持这一点。我相信document.write()如果在页面已打开的情况下使用它会很快。
这是应该就地替换document.write的代码:
1 2 3 4 5
| document.write=function(s){
var scripts = document.getElementsByTagName('script');
var lastScript = scripts[scripts.length-1];
lastScript.insertAdjacentHTML("beforebegin", s);
} |
-
不错的提示。是跨浏览器吗?我已经在Chrome上对其进行了测试,并且可以正常工作。
-
如果页面上没有脚本,这不起作用吗?
-
好吧,至少在页面上(无论您将函数放在哪里),但是如果唯一的脚本位于 head>中怎么办?他提到的关键是insertAdjacentHTML函数。
-
奇怪,直到今天,我还没有收到有人评论的电子邮件。 @Pons-应该是跨浏览器,但是我不了解IE。
-
@Noyo-通常在页面内部使用document.write,例如Github GIST:gist.github.com/adriank/7436248.js
-
或更简单地说:document.write = function (str){ document.body.insertAdjacentHTML("beforeend", str); }
-
@skibulk:虽然这在某些情况下可以使用,但没有在其他HTML(例如,页面中间的广告)中插入的好处。
只是在这里说一个注释,尽管由于性能方面的考虑(同步DOM注入和评估),人们对使用document.write非常不满意,但是如果使用document.write注入脚本标签,也没有实际的1:1替代方案。一经请求。
有很多很好的方法可以避免这样做(例如,像RequireJS这样的脚本加载器来管理您的依赖链),但是它们更具侵入性,因此最好在整个站点/应用程序中使用。
作为document.write的推荐替代方法,您可以使用DOM操作直接查询节点元素并将其添加到DOM。
-
不要只是把链接。
-
如果它解决了为什么document.write有问题的问题,这将是一个更好的答案。
问题取决于您实际要做什么。
通常,代替执行document.write,可以使用someElement.innerHTML或更好的document.createElement和someElement.appendChild。
您也可以考虑使用jQuery之类的库,并在其中使用修改功能:http://api.jquery.com/category/manipulation/
这可能是最正确,直接的替代方法:insertAdjacentHTML。
尝试使用getElementById()或getElementsByName()访问特定元素,然后使用innerHTML属性:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <html>
<body>
</body>
<script type="text/javascript">
var myDiv1 = document.getElementById("myDiv1");
var myDiv2 = document.getElementById("myDiv2");
myDiv1.innerHTML ="Content of 1st DIV";
myDiv2.innerHTML ="Content of second DIV element";
</html> |
-
没有完全解决。您在脚本中不需要标记和<\b>吗?
-
@DarkLightA:您输入的默认源与上面的源不同。另一方面,它在javascript窗口中!来源具有html和javascript两种来源类型。使用该源在桌面上创建一个html文件并打开它。
您可以结合使用insertAdjacentHTML方法和document.currentScript属性。
Element接口的insertAdjacentHTML()方法将指定的文本解析为HTML或XML,并将结果节点插入到DOM树中的指定位置:
-
'beforebegin':在元素本身之前。
-
'afterbegin':就在元素内部,在其第一个子元素之前。
-
'beforeend':在元素的最后一个子元素之后。
-
'afterend':在元素本身之后。
Document.currentScript属性返回当前正在处理其脚本的元素。最佳位置是在开始之前-新的HTML将在本身之前插入。
1 2 3 4
| document.currentScript.insertAdjacentHTML(
'beforebegin',
'this is the document.write alternative'
); |
-
尽管这可以回答问题,但请提供任何解释,以确保人们了解此处发生的情况。
我看不到document.write的问题。如果您想在onload事件触发之前使用它(例如,大概是要从结构化数据中构建元素),则它是适合使用的工具。构建insertAdjacentHTML或将其显式添加到DOM后,没有性能优势。我只是用一个旧脚本对它进行了三种不同的测试,该脚本曾经用于安排4个调制解调器组中24/7服务的传入调制解调器呼叫。
到完成时,此脚本将创建3000多个DOM节点,主要是表单元。在运行Vista的Firefox上使用7年的旧PC上,使用本地12kb源文件中的document.write和三个可重复使用2000次的1px GIF,只需不到2秒的时间。该页面会弹出,显示完整的状态,可以处理事件。
使用insertAdjacentHTML不能直接替代,因为浏览器会关闭脚本需要保持打开状态的标记,并且最终花费两倍的时间才能最终创建变形的页面。将所有片段写入字符串,然后将其传递给insertAdjacentHTML会花费更长的时间,但是至少您可以按设计获得页面。其他选项(例如一次手动重新构建一个节点的DOM)是如此荒谬,以至于我什至不去。
有时document.write是要使用的东西。它是JavaScript中最古老的方法之一,这一事实并不是要反对它,而是要支持它-它是经过高度优化的代码,可以准确地实现其意图并自诞生以来就一直在这样做。
很高兴知道还有其他可供选择的后加载方法,但是必须理解,这些方法完全旨在用于不同的目的。即在创建DOM并为其分配内存后修改DOM。如果您的脚本旨在编写HTML的内容,那么使用这些方法在本质上会占用大量资源,而浏览器首先会从中创建HTML。
只需编写它,然后让浏览器和解释器完成工作即可。那就是他们的目的。
PS:我刚刚在body标记中使用onload参数进行了测试,即使在这一点上,文档仍然是open和document.write()正常运行的功能。此外,最新版本的Firefox中的各种方法之间也没有明显的性能差异。当然,硬件/软件堆栈中的某处可能会进行大量缓存,但这确实是要点-让机器完成工作。不过,这可能会在廉价智能手机上有所作为。干杯!
我不确定这是否会正常工作,但我想到了
1 2 3
| var docwrite = function(doc) {
document.write(doc);
}; |
这为我解决了错误消息的问题。