【问题标题】:JavaScript - controlling the insertion point for document.writeJavaScript - 控制 document.write 的插入点
【发布时间】:2013-02-01 02:44:48
【问题描述】:

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

我的页面不是 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 插入点?有没有人知道如何做到这一点?

【问题讨论】:

  • 第三方脚本下载了吗,可以编辑吗?我认为这可能是比黑客攻击document.write() 更好的解决方案
  • 我的例子确实通过了。我的意思是:document.write('' + '文本内容' + '')
  • 我可以编辑它,但是除了完整的 JS 解析之外,有没有办法保证编辑后的代码能够正常运行?

标签: javascript document.write


【解决方案1】:

如果您正在处理第 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 的情况下使用。

【讨论】:

  • 当我使用这段代码时,Chrome 对我咆哮并抛出错误:'Uncaught SyntaxError: Unexpected token ILLEGAL'
【解决方案2】:

可以覆盖 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

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

【讨论】:

    【解决方案3】:

    编辑前的原始答案:


    基本上document.write的问题在于does not work in XHTML documents。那么最广泛的解决方案(尽管看起来很苛刻)是不为您的页面使用 XHTML/xml。由于 IE+XHTML 和mimetype problem,Google Adsense 崩溃(可能是件好事 :),以及向 HTML5 的普遍转变,我认为它并没有看起来那么糟糕。

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

    重新阅读您的问题,您对 John 的脚本有什么具体问题吗?众所周知,它在 Safari 2.0 中会失败,但仅此而已。

    【讨论】:

    • 我的页面没有使用 XHTML,但是我在加载 DOM 后加载了第 3 方脚本,它们覆盖了我的页面。我的问题是以下代码将失败: document.write('document.write('>' + '文本内容' + 'document.write('\div>');
    • @yeeeev:哇,所以这与 XHTML 无关?您确实应该将该代码作为代码 sn-p 放入您的问题中,以便我们可以更好地帮助您。它错误地显示为评论。
    • @yeeev:我看到您实际上已经尝试将其放入。让我编辑你的问题....
    【解决方案4】:

    您可能对the Javascript library I developed 感兴趣,它允许使用 document.write window.onload 之后加载第 3 方脚本。在内部,该库覆盖 document.write,动态添加 DOM 元素,运行任何包含的脚本,这些脚本也可能使用 document.write。

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

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

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

    我已设置a demo, in which I load 3 Google Ads, an Amazon widget as well as Google Analytics dynamically

    【讨论】:

      【解决方案5】:

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

      【讨论】:

        【解决方案6】:

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

        【讨论】:

          【解决方案7】:

          有更好的方法来做到这一点。 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>
          

          【讨论】:

          • 如果您无法更改第 3 方脚本,此解决方案将毫无用处。解决方案#2也将用“hello world”替换整个身体。错字?
          • @gregers。这只是该技术的一个示例。
          猜你喜欢
          • 2010-09-08
          • 2012-04-11
          • 1970-01-01
          • 1970-01-01
          • 2011-06-27
          • 1970-01-01
          • 2014-07-16
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多