动态地将javascript插入使用document.write的HTML中

时间:2020-03-05 18:50:41  来源:igfitidea点击:

我当前正在加载灯箱样式弹出窗口,该弹出窗口将从XHR调用中加载HTML。然后,使用" element.innerHTML = content"在"模式"弹出窗口中显示此内容。这就像一个超级按钮。

在该网站的另一部分中,我使用Flickr'徽章'(http://www.elliotswan.com/2006/08/06/custom-flickr-badge-api-documentation/)动态加载flickr图像。这是通过包含一个脚本标签来完成的,该脚本标签加载了flickr javascript,而JavaScript脚本又执行了一些document.write语句。

当它们包含在HTML中时,两者都可以完美地工作。仅在将flickr徽章代码加载到灯箱中时,根本不会呈现任何内容。似乎使用innerHTML来编写document.write语句已走得太远了,但是我无法在此行为的javascript实现(FF2&3,IE6&7)中找到任何线索。

任何人都可以澄清这是否应该工作吗?谢谢。

解决方案

回答

我可以先得到一些澄清以确保我解决问题吗?

document.write调用会将内容添加到标记中出现标记的位置。例如,如果我们在函数中包含document.write调用,但在其他地方调用该函数,则document.write输出将发生在标记中定义函数的地方,而不是在调用它的地方。

因此,为了使它在所有Flickr上都能正常工作,声明将需要成为element.innerHTML = content中的content的一部分。确实是这样吗?

我们可以通过在设置为innerHTML的内容中添加一个简单的document.write`调用来快速测试此操作是否完全奏效,并查看其作用:

<script>
  var content = "<p>1st para</p><script>document.write('<p>2nd para</p>');</script>"
  element.innerHTML = content;
</script>

如果这行得通,在内容集中设置为元素的" innerHTML"的" document.write"的概念可能就行了。

我的直觉是它不会起作用,但是测试该概念应该非常简单。

回答

我创建了一个简单的测试页面来说明问题:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
    <head>
        <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
        <title>Document Write Testcase</title>
    </head>
    <body>
        <div id="container">
        </div>
        <div id="container2">
        </div>

        <script>
            // This doesn't work!
            var container = document.getElementById('container');
            container.innerHTML = "<script type='text/javascript'>alert('foo');document.write('bar');<\/script>";

            // This does!
            var container2 = document.getElementById('container2');
            var script = document.createElement("script");
            script.type = 'text/javascript';
            script.innerHTML = "alert('bar');document.write('foo');";
            container.appendChild(script);
        </script>
    </body>
</html>

此页面会提示" bar"并显示" foo",而我希望它也会提示" foo"并显示" bar"。但是,不幸的是,由于script标签是一个较大的HTML页面的一部分,因此我无法像上面的示例那样单独选择该标签并添加它。好吧,我可以,但是那需要扫描innerHTML内容中的script标记,并用占位符将它们替换为字符串,然后使用DOM插入它们。听起来并不那么琐碎。

回答

因此,我们使用DOM方法创建一个script元素并将其添加到现有元素上,然后导致添加的script元素的内容执行?听起来不错。

我们说脚本标签是较大的HTML页面的一部分,因此无法被选中。我们能否不给脚本标签一个ID并将其作为目标?我可能在这里缺少明显的东西。

回答

从理论上讲,是的,我可以这样选择脚本标签。问题是我们可能会在许多情况下发生这种情况,因此我正在尝试查找此行为的某些原因或者文档。

另外,script标签在加载后似乎不再是DOM的一部分。在我们的环境中,我的containerdiv保持为空,因此无法获取script标签。不过,它应该起作用,因为在上面的示例中脚本没有执行,但仍然是DOM的一部分。

回答

document.write即将被淘汰。不过,由于JavaScript的奇妙之处,我们可以将自己的函数分配给document对象的write方法,该对象在我们选择的元素上使用innerHTML来添加提供的内容。

回答

通常,使用innerHTML时不会执行脚本标签。在情况下,这很好,因为对document.write的调用将清除掉页面中已经存在的所有内容。但是,这使我们不必再添加任何HTML document.write。

jQuery的HTML操作方法将为我们执行HTML脚本,其窍门是捕获对document.write的调用,并将HTML放置在正确的位置。如果足够简单,那么将执行以下操作:

var content = '';
document.write = function(s) {
    content += s;
};
// execute the script
$('#foo').html(markupWithScriptInIt);
$('#foo .whereverTheDocumentWriteContentGoes').html(content);

虽然它变得复杂。如果脚本在另一个域上,它将被异步加载,因此我们必须等到完成后才能获取内容。另外,如果它只是将HTML写入片段的中间而没有可以轻松选择的包装元素呢? writeCapture.js(完全公开:我写了它)解决了所有这些问题。我建议只使用它,但至少我们可以查看代码以了解其如何处理所有内容。

编辑:这是一个页面,展示听起来像我们想要的效果。