17

我想创建一个运行 3rd 方脚本的页面,该脚本包含document.write在 DOM 已经完全加载之后。

我的页面不是 XHTML。我的问题是 document.write 覆盖了我自己的页面。(这是加载 DOM 后所做的事情)。

我尝试覆盖 document.write 函数(以类似于http://ejohn.org/blog/xhtml-documentwrite-and-adsense/的方式),但这不包括 document.write 包含部分标签的情况。

一个会破坏上述代码的例子是:

document.write("<"+"div");
document.write(">"+"Done here<"+"/");
document.write("div>");

有没有办法通过 JavaScript 修改 document.write 插入点?有没有人有更好的想法如何做到这一点?

4

7 回答 7

11

如果您正在处理第 3 方脚本,仅替换 document.write 以捕获输出并将其粘贴在正确的位置是不够的,因为他们可能会更改脚本,然后您的网站就会崩溃。

writeCapture.js 可以满足您的需求(完全披露:我是作者)。它基本上重写了脚本标签,以便每个标签都捕获自己的document.write输出并将其放在正确的位置。用法(使用 jQuery)将类似于:

$(document.body).writeCapture().append('<script type="text/javascript" src="http://3rdparty.com/foo.js"></script>');

在这里,我假设您要附加到正文的末尾。所有 jQuery 选择器和操作方法都可以与该插件一起使用,因此您可以将其注入到任何地方,并且可以随心所欲。如果有问题,它也可以在没有 jQuery 的情况下使用。

于 2009-12-29T16:16:06.147 回答
4

可以覆盖 document.write 方法。因此,您可以缓冲发送到 document.write 的字符串,并将缓冲区输出到您喜欢的任何位置。但是,如果处理不当,将脚本从同步更改为异步可能会导致错误。这是一个例子:

简化的 document.write 替换

(function() {
    // WARNING: This is just a simplified example
    // to illustrate a problem.
    // Do NOT use this code!

    var buffer = [];
    document.write = function(str) {
        // Every time document.write is called push
        // the data into buffer. document.write can
        // be called from anywhere, so we also need
        // a mechanism for multiple positions if
        // that's needed.
        buffer.push(str);
    };

    function flushBuffer() {
        // Join everything in the buffer to one string and put
        // inside the element we want the output.
        var output = buffer.join('');
        document.getElementById("ad-position-1").innerHTML = output;
    }

    // Inject the thid-party script dynamically and
    // call flushBuffer when the script is loaded
    // (and executed).
    var script = document.createElement("script");
    script.onload = flushBuffer;
    script.src = "http://someadserver.com/example.js";

})();

http://someadserver.com/example.js的内容

var flashAdObject = "<object>...</object>";
document.write("<div id='example'></div>");

// Since we buffer the data the getElementById will fail
var example = document.getElementById("example");
example.innerHTML = flashAdObject; // ReferenceError: example is not defined

我已经记录了我在编写和使用 document.write 替换时遇到的不同问题:https ://github.com/gregersrygg/crapLoader/wiki/What-to-think-about-when-replacing-document.write

但是使用 document.write 替换的危险是所有可能出现的未知问题。有些甚至无法绕过。

document.write("<scr"+"ipt src='http://someadserver.com/adLib.js'></scr"+"ipt>");
adLib.doSomething(); // ReferenceError: adLib is not defined

幸运的是,我没有在野外遇到上述问题,但这并不能保证它不会发生;)

还想试试吗?试试crapLoader(我的)或writeCapture

您还应该检查友好的 iframes。基本上,它会创建一个同域 iframe 并在那里加载所有内容,而不是在您的文档中。不幸的是,我还没有找到任何好的库来处理这个问题。

于 2012-06-11T09:13:09.633 回答
3

编辑前的原始答案:


基本上问题document.write在于它在 XHTML 文档中不起作用。那么最广泛的解决方案(尽管看起来很苛刻)是不要为您的页面使用 XHTML/xml。由于 IE+XHTML 和mimetype 问题,Google Adsense 中断(可能是一件好事 :),以及向 HTML5 的普遍转变,我认为这并不像看起来那么糟糕。

但是,如果您真的想为您的页面使用 XHTML,那么您链接到的 John 的脚本是您目前所拥有的最好的脚本。只需在服务器上嗅探 IE。如果请求来自 IE,则不要执行任何操作(并且不要提供application/xhtml+xmlmimetype!)。否则,将其放入<head>您的页面中,您就可以参加比赛了。

重新阅读你的问题,你对约翰的剧本有什么特别的问题吗?众所周知,它在 Safari 2.0 中会失败,但仅此而已。

于 2009-10-08T11:03:18.863 回答
3

您可能对我开发的 Javascript 库感兴趣,它允许在window.onload之后使用 document.write 加载 3rd 方脚本。在内部,该库覆盖 document.write,动态附加 DOM 元素,运行任何可能使用 document.write 的包含脚本。

与 John Resig 的解决方案(这是我自己的代码灵感的一部分)不同,我开发的模块支持部分写入,例如您使用 div 给出的示例:

document.write("<"+"div");
document.write(">"+"Done here<"+"/");
document.write("div>");

我的库将在解析和呈现标记之前等待脚本结束。在上面的示例中,它将使用完整的字符串运行一次,"<div>Done here</div>"而不是使用部分标记运行 3 次。

我设置了一个演示,其中我加载了 3 个 Google Ads、一个 Amazon 小部件以及动态的 Google Analytics

于 2009-11-22T21:58:23.073 回答
1

FWIW,我发现postscribe是这些天最好的选择 - 它处理包装一个讨厌的广告渲染模块,就像一个魅力,让我们的页面加载而不会被阻止。

于 2013-01-31T18:44:48.707 回答
0

为了在 DOM 渲染后更改页面的内容,您需要使用 javascript 库在某些点(jQuery、mootools、原型等)附加 HTML 或文本,或者只使用每个 DOM 的 innerHTML 属性元素来更改/附加文本。这适用于跨浏览器,不需要任何库。

于 2009-10-10T10:34:00.190 回答
-2

有更好的方法来做到这一点。2种方式

1) 追加

<html><head>
<script>
  window.onload = function () {
    var el = document.createTextNode('hello world');
    document.body.appendChild(el);
  }
</script></head><body></body></html>

2) 内部HTML

<html><head><script>
  window.onload = function () {
    document.body.innerHTML = 'hello world';
  }
</script></head><body></body></html>
于 2009-10-12T15:39:17.510 回答