什么是document.write的替代品?


71

在教程中,我学会了使用document.write。现在,我了解到很多人对此表示反对。我已经尝试过了print(),但是它确实将其发送到打印机。

那么我应该使用哪些替代方法,为什么不使用document.write呢?w3schools和MDN都使用document.write


3
print()决定解决window.print()
Alex


2
JavaScript的print()与PHP的不同print()。JS从字面上将页面发送到打印机,而PHP仅输出代码。
德拉扎

Answers:



86

替换HTML的原因是由于JavaScript函数邪恶:document.write()

它绝对是“错误的形式”。仅当您在页面加载时使用它时,它才适用于网页。如果在运行时使用它,它将用输入替换整个文档。而且,如果您将其应用为严格的XHTML结构,那么它甚至不是有效的代码。


问题:

document.write写入文档流。调用document.write一个关闭(或加载)文件自动调用document.open这将清除文件。

-来自MDN的报价

document.write()有两个伴郎document.open(),和document.close()。加载HTML文档时,该文档为“打开”状态。 文档加载完成后,文档已“关闭”。此时使用document.write()会擦除整个(关闭的)HTML文档,并用新的(打开的)文档替换。这意味着您的网页已被擦除,并开始从头开始编写新页面。

我相信document.write()也会导致浏览器的性能下降(如果我错了,请纠正我)。


一个例子:

此示例在页面加载后将输出写入HTML文档。document.write()当您按下“灭”按钮时,Watch的邪恶力量会清除整个文档:

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其他示例的示例:

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 <code>.innerHTML</code> with <code>document.write()</code> 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解决方案证明是不同步的
鲍勃·斯坦

2
@ Godisgood,document.write绝对不会出现性能问题,因为它与浏览器加载初始HTTP响应时使用的功能完全相同。
Pacerier's

@Pacerier是的,但是我的意思document.write()是页面加载后使用起来较慢,因为它必须清除文档,然后在每次调用该函数时重新打开它。.innerHTML不会执行任何操作,因此我可以肯定我读到它毕竟更快。我将寻找一个来源来支持这一点。我相信document.write()如果您在页面已打开的情况下使用它会很快。
德拉扎

24

这是应该就地替换document.write的代码:

document.write=function(s){
    var scripts = document.getElementsByTagName('script');
    var lastScript = scripts[scripts.length-1];
    lastScript.insertAdjacentHTML("beforebegin", s);
}

不错的提示。是跨浏览器吗?我已经在Chrome上对其进行了测试,并且可以正常工作。
2014年

2
如果页面上没有脚本,这不行吗?
Noyo 2014年

好吧,至少在页面上(无论您将函数放在哪里),但是如果唯一的脚本位于<head> </ head>中怎么办?他提到的关键是insertAdjacentHTML函数。
Lonnie Best

奇怪,直到今天,我还没有收到有人发表评论的电子邮件。@Pons-应该是跨浏览器,但是我不了解IE。
Adrian Kalbarczyk 2014年

@Noyo-通常您在页面的<script>内使用document.write,例如Github GIST:gist.github.com/adriank/7436248.js
Adrian Kalbarczyk

10

只是在这里说一点document.write便是,尽管由于性能方面的考虑(同步DOM注入和评估)而使使用倍受争议,但是如果您要按需注入脚本标记,也没有实际的1:1替代方法document.write

有很多很好的方法来避免这样做(例如,像RequireJS这样的脚本加载器来管理您的依赖链),但是它们更具侵入性,因此最好在整个站点/应用程序中使用。


9

您可以结合使用insertAdjacentHTML方法和document.currentScript属性。

insertAdjacentHTML()Element接口的方法将指定的文本解析为HTML或XML,并将结果节点插入DOM树中的指定位置

  • 'beforebegin':元素本身之前。
  • 'afterbegin':在元素内,在其第一个子元素之前。
  • 'beforeend':在元素的最后一个子元素之后。
  • 'afterend':元素本身之后。

document.currentScript属性返回<script>当前正在处理其脚本的元素。最佳位置是在开始之前-新的HTML会在<script>其自身之前插入。为了匹配document.write的本机行为,可以文本放置afterend后面,但是连续调用该函数的节点的放置顺序与您调用它们的顺序不同(就像document.write这样),但是相反。HTML的显示顺序可能比它们相对于<script>标记的放置位置更为重要,因此要使用beforebegin

document.currentScript.insertAdjacentHTML(
  'beforebegin', 
  'This is a document.write alternative'
)


尽管这可能会回答问题,但是请提供任何解释,以确保人们了解此处发生的情况。
兰迪

感谢这里的评论,我的问题得以解决,我在这里解释了问题所在以及对我
有用的

7

问题取决于您实际要做什么。

通常,使用而不是document.write可以使用someElement.innerHTML或更佳document.createElement的选择someElement.appendChild

您还可以考虑使用类似jQuery的库并在其中使用修改功能:http : //api.jquery.com/category/manipulation/



4

尝试使用getElementById()或getElementsByName()访问特定元素,然后使用innerHTML属性:

<html>
    <body>
        <div id="myDiv1"></div>
        <div id="myDiv2"></div>
    </body>

    <script type="text/javascript">
        var myDiv1 = document.getElementById("myDiv1");
        var myDiv2 = document.getElementById("myDiv2");

        myDiv1.innerHTML = "<b>Content of 1st DIV</b>";
        myDiv2.innerHTML = "<i>Content of second DIV element</i>";
    </script>
</html>

还没有完全解决。您不需要<\/b>脚本中的<body>标签吗?
DarkLightA 2010年

@DarkLightA:您输入的默认源与上面的源不同。另一方面,它在javascript窗口中!来源具有html和javascript两种来源类型。使用该源在桌面上创建一个html文件并打开它。

4

我看不到的问题document.write。如果您想在onload事件触发之前使用它(例如,大概是要从结构化数据中构建元素),则它是适合使用的工具。insertAdjacentHTML在DOM构建之后使用或显式添加节点到DOM并没有性能优势。我只是用一个旧脚本对它进行了三种不同的测试,我曾经使用该脚本在4个调制解调器的银行中为24/7服务安排传入的调制解调器呼叫。

到完成时,此脚本将创建3000多个DOM节点,主要是表单元。在运行Vista的Firefox上使用7年的旧PC上,使用document.write本地12kb源文件和三个1px GIF(可重复使用约2000次)的时间不到2秒。该页面会弹出,显示完整的状态,可以处理事件。

使用insertAdjacentHTML不是直接替代方法,因为浏览器会关闭脚本需要保持打开状态的标签,并且最终需要花费两倍的时间来创建一个变形的页面。将所有片段insertAdjacentHTML写成字符串,然后传递给它花费的时间甚至更长,但是至少您可以按设计获得页面。其他选项(例如一次手动重新构建一个节点的DOM)是如此荒谬,以至于我什至不去。

有时document.write是要使用的东西。它是JavaScript中最古老的方法之一,这一事实并不是要反对它,而是要支持它-它是经过高度优化的代码,它完全符合其意图并自诞生以来就一直在做。

很高兴知道还有其他可供选择的后加载方法,但是必须理解,这些方法完全旨在用于不同的目的。即在创建DOM并为其分配内存后修改DOM。如果您的脚本旨在编写HTML,而浏览器首先从中创建DOM,则使用这些方法本质上会占用更多资源。

只需编写它,然后让浏览器和解释器完成工作即可。那就是他们的目的。

PS:我只是使用测试onload在参数body标签,甚至在这一点上的文档仍然是opendocument.write()发挥预期的作用。另外,最新版本的Firefox中的各种方法之间也没有明显的性能差异。当然,在硬件/软件堆栈中的某处可能有大量的缓存,但这确实是要点-让机器完成工作。不过,这在廉价智能手机上可能会有所作为。干杯!


-5

我不确定这是否会正常工作,但我想到了

var docwrite = function(doc) {               
    document.write(doc);          
};

这为我解决了错误消息的问题。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.