为什么将 <script> 附加到动态创建的 <iframe> 似乎在父页面中运行脚本?

IT技术 javascript jquery dynamic iframe parent
2021-02-06 23:30:35

我正在尝试使用 JavaScript 创建一个 <iframe>,然后将一个 <script> 元素附加到该 <iframe>,我想在 <iframe>d 文档的上下文中运行该元素。

不幸的是,我似乎做错了什么 - 我的 JavaScript 似乎成功执行,但 <script> 的上下文是父页面,而不是 <iframe>d 文档。当浏览器请求iframe_test.js 时我还在 Firebug 的“Net”选项卡中收到 301 错误,但它随后再次请求它(不知道为什么?)成功。

这是我正在使用的代码(http://onespot.wsj.com/static/iframe_test.html 上的现场演示):

iframe_test.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title>&lt;iframe&gt; test</title>
  </head>
  <body>
    <div id="bucket"></div>
    <script type="text/javascript" src="http://jqueryjs.googlecode.com/files/jquery-1.3.2.min.js"></script>
    <script type="text/javascript">
      $(document).ready(function() {
        $('#bucket').append('<iframe id="test"></iframe>');
        setTimeout(function() {
          var iframe_body = $('#test').contents().find('body');
          iframe_body.append('<scr' + 'ipt type="text/javascript" src="http://onespot.wsj.com/static/iframe_test.js"></scr' + 'ipt>');
        }, 100);
      });
    </script>
  </body>
</html>

iframe_test.js

$(function() {
  var test = '<p>Shouldn\'t this be inside the &lt;iframe&gt;?</p>';
  $('body').append(test);
});

看起来不寻常的一件事是iframe_test.js 中的代码甚至可以工作;我没有在 <iframe> 本身中加载 jQuery,只有在父文档中。这对我来说似乎是一个线索,但我无法弄清楚这意味着什么。

任何想法,建议等将不胜感激!

3个回答

有同样的问题,我花了几个小时才找到解决方案。您只需要使用iframe 的 document创建脚本的对象

var myIframe = document.getElementById("myIframeId");
var script = myIframe.contentWindow.document.createElement("script");
script.type = "text/javascript";
script.src = src;
myIframe.contentWindow.document.body.appendChild(script);

奇迹般有效!

@StanJames :不知道,但这通常会导致在没有 ᴄᴏʀꜱ 的情况下跨 AJAX。
2021-03-20 23:30:35
太棒了......从几个小时开始就在做同样的事情......现在已经修复了
2021-03-25 23:30:35
@StanJames 跨域 iframe 是完全不同的球类游戏。即使有解决方案,浏览器也会很快找到它们。这是一项安全功能,可防止坏人破解您的银行密码等。
2021-03-25 23:30:35
@user2284570 有没有办法做到这一点跨域?
2021-03-27 23:30:35
顺便说一句,为了浏览器兼容性,我建议在内容窗口中使用它: var doc = iframe.contentDocument ? iframe.contentDocument : (iframe.contentWindow ? iframe.contentWindow.document : iframe.document);
2021-04-01 23:30:35

我没有找到原始问题的答案,但我确实找到了另一种效果更好的方法(至少对我而言是这样)。

这不会在父页面上使用 jQuery(这实际上是一件好事,因为我不想在那里加载它),但它确实以一种显然完全有效和可用的方式在 <iframe> 中加载了 jQuery。我所做的只是用一个从头开始创建的新对象来覆盖 <iframe> 的文档对象。这允许我简单地在字符串中包含一个 <script> 元素,然后我将其写入 <iframe> 的文档对象。

代码:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title>frame</title>
  </head>
  <body>

    <div id="test"></div>

    <script type="text/javascript">
      // create a new <iframe> element
      var iframe = document.createElement('iframe');

      // append the new element to the <div id="bucket"></div>
      var bucket = document.getElementById('test');
      bucket.appendChild(iframe);

      // create a string to use as a new document object
      var val = '<scr' + 'ipt type="text/javascript" src="http://jqueryjs.googlecode.com/files/jquery-1.3.2.min.js"></scr' + 'ipt>';
      val += '<scr' + 'ipt type="text/javascript"> $(function() { $("body").append("<h1>It works!</h1>"); }); </scr' + 'ipt>';

      // get a handle on the <iframe>d document (in a cross-browser way)
      var doc = iframe.contentWindow || iframe.contentDocument;
      if (doc.document) {
        doc = doc.document;
      }

      // open, write content to, and close the document
      doc.open();
      doc.write(val);
      doc.close();
    </script>

  </body>
</html>

我希望这可以帮助有人在路上!

在 iframe 中粘贴包含 script 标签的整个 html 内容时真的很有帮助
2021-03-14 23:30:35
为什么写'<scr' + 'ipt而不是'<script直接?
2021-03-17 23:30:35
@user2284570:浏览器会<script>逐字解释内联标签内的任何 HTML 字符串,因此类似的内容var endScript = '</script>';会被解释为当前脚本的过早结束标签,从而导致语法错误。
2021-03-18 23:30:35
但这有缺点,因为doc.write只有在加载整个页面时才开始写入。
2021-03-25 23:30:35
这正是我正在寻找的。有什么方法可以附加到 iframe 以便正文内容不会被删除?
2021-04-06 23:30:35

原始问题的答案很简单 - 脚本的执行是由 jquery 完成的,并且由于 jquery 加载在顶部框架中,因此无论您将它附加到何处,这也是脚本运行的地方。毫无疑问,jquery 的一个更智能的实现可以使用正确的 window 对象,但现在事情就是这样。

至于解决方法,您已经有了两个很好的答案(即使一个是您自己的)。我可能要补充的是,您可以使用其中一种解决方法将 jquery.js 包含在 iframe 中,然后获取该 jquery 对象而不是顶部的对象来插入您的附加标记……但这也很可能太过分了。