76

在教程中,我学会了使用document.write. 现在我明白了,许多人对此不以为然。我试过print()了,但它确实将它发送到打印机。

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

4

11 回答 11

93

您的 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 文档。当您按下“消灭”按钮时, Watchdocument.write()的邪恶力量会清除整个文档:

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>

于 2014-12-17T17:14:42.100 回答
26

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

document.write=function(s){
    var scripts = document.getElementsByTagName('script');
    var lastScript = scripts[scripts.length-1];
    lastScript.insertAdjacentHTML("beforebegin", s);
}
于 2013-11-03T20:28:47.307 回答
15

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

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

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

document.currentScript属性返回<script>当前正在处理其脚本的元素。最佳位置是beforebegin — 新的 HTML 将插入到<script>它自己之前。为了匹配document.write的本机行为,可以将文本放置在end 之后,但是随后对函数的连续调用中的节点不会按照您调用它们的顺序(就像document.write那样)放置,而是相反。HTML 出现的顺序可能比它们相对于<script>标签的位置更重要,因此使用beforebegin

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

于 2016-08-11T21:49:05.783 回答
13

作为推荐的替代方法,document.write您可以使用DOM 操作直接查询节点元素并将其添加到 DOM。

于 2010-12-27T10:15:34.883 回答
12

只是在这里放一个注释说,尽管document.write由于性能问题(同步 DOM 注入和评估)而非常不赞成使用,但如果您使用按需注入脚本标签,也没有实际的 1:1 替代方案。document.write

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

于 2012-11-21T18:38:36.860 回答
8

我看不到document.write. 例如,如果您在onload事件触发之前使用它来从结构化数据构建元素,那么它就是合适的工具。insertAdjacentHTML在构建 DOM 之后使用或显式添加节点到 DOM 没有性能优势。我刚刚使用一个旧脚本以三种不同的方式对其进行了测试,该脚本曾经用于为一组 4 个调制解调器上的 24/7 服务安排传入的调制解调器呼叫。

到它完成时,这个脚本创建了超过 3000 个 DOM 节点,主要是表格单元格。在一台运行 Firefox 的 7 年旧 PC 上的 Vista 上,这个小练习只用了不到 2 秒的时间,使用document.write了一个本地 12kb 源文件和三个 1px 的 GIF,这些 GIF 被重复使用了大约 2000 次。该页面刚刚完全形成,准备好处理事件。

使用insertAdjacentHTML不是直接替代品,因为浏览器会关闭脚本需要保持打开状态的标签,并且最终创建一个损坏的页面需要两倍的时间。将所有部分写入一个字符串,然后将其传递给它insertAdjacentHTML需要更长的时间,但至少你得到了设计的页面。其他选项(比如一次手动重新构建一个节点的 DOM)太荒谬了,我什至不会去那里。

有时document.write是要使用的东西。它是 JavaScript 中最古老的方法之一这一事实并不是反对它,而是有利于它的一点——它是高度优化的代码,它完全按照它的意图去做,并且从一开始就一直在做。

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

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

PS:我刚刚onload在标签中使用了一个参数进行了测试,即使在这一点上,body文档仍然可以按预期运行。此外,在最新版本的 Firefox 中,各种方法之间没有明显的性能差异。当然,硬件/软件堆栈中的某个地方可能会进行大量缓存,但这才是真正的重点——让机器来完成工作。不过,它可能会对便宜的智能手机产生影响。干杯!opendocument.write()

于 2015-11-02T07:12:46.157 回答
7

这个问题取决于你实际上想要做什么。

通常,document.write您可以使用someElement.innerHTML或更好地document.createElement使用someElement.appendChild.

您还可以考虑使用像 jQuery 这样的库并使用其中的修改函数:http ://api.jquery.com/category/manipulation/

于 2010-12-27T10:21:58.560 回答
6

这可能是最正确、最直接的替换:insertAdjacentHTML

于 2013-04-18T20:35:41.757 回答
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>
于 2010-12-27T10:16:58.917 回答
0

采用

var  documentwrite =(value, method="", display="")=>{
            switch(display) {
                case "block":
                 var x = document.createElement("p");
                  break;
                  case "inline":
                 var x = document.createElement("span");
                  break;
                default:
                 var x = document.createElement("p");
              }
            
            var t = document.createTextNode(value);
            x.appendChild(t);
            
            if(method==""){
             document.body.appendChild(x);
            }
            else{
            document.querySelector(method).appendChild(x);
           
            }
        }

并根据您的要求调用该函数,如下所示

  documentwrite("My sample text"); //print value inside body
  documentwrite("My sample text inside id", "#demoid", "block");  // print value inside id and display block
  documentwrite("My sample text inside class", ".democlass","inline"); // print value inside class and and display inline 
于 2021-07-03T10:00:42.793 回答
-6

我不确定这是否会完全有效,但我想到了

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

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

于 2015-11-09T04:58:47.550 回答