如何使用jQuery将JavaScript代码添加到现有的iFrame中?

22
我想使用jQuery将一个JavaScript片段添加到页面中现有的iFrame中。我有以下代码...
代码:
content = "<script>" + js_code + "</script>";

$('#iframe_id').contents().find('body').append(content);

但不知何故它没有起作用。我查看了一些现有/相关的答案,似乎jQuery并不能完全将脚本标签识别为脚本标签。iFrame与同一域/同一端口/同一主机位于同一位置,因此不存在跨站点脚本等问题。我该如何解决这个问题?


是的...iFrame的内容属于我,基本上是同一域名。 - Gandalf
@Gandalf 这段代码片段是嵌入在标记内 (<script>...</script>) 还是在单独的 .js 文件中? - Jonathan Lonowski
此代码片段将仅位于(script)标签中... - Gandalf
有趣.. 试试这个: frames[0].window.$ = frames[0].window.jQuery = window.$; - Ivan Chernykh
谢谢...但它没有起作用。 - Gandalf
显示剩余3条评论
8个回答

31
问题在于如果您的脚本中包含关闭脚本标签(</script>),HTML解析器会混淆并提前关闭脚本标签。
解决方法是在 "<\/script>" 中转义 /。这是因为在JavaScript(和其他一些语言)中,任何无效的转义序列都将被忽略,因此"\l"被视为"l""\/"被视为"/"。然而,HTML解析器不使用反斜杠来转义它们,因此它不会混淆(感谢https://stackoverflow.com/users/405681/keaukraine)。
var scriptTag = "<script>alert(1)<\/script>";
$("#iframe").contents().find("body").append(scriptTag);

原始解决方案

拆分结束标签,以避免破坏HTML解析器。本页面上的其他解决方案之所以有效,是因为它们从未在代码中使用字符串</script>jsfiddle):

var scriptTag = "<script>alert(1)<";
scriptTag +=  "/script>";
console.log(scriptTag);
$("#iframe").contents().find("body").append(scriptTag);

或者(jsfiddle):

var scriptTag = "<script>alert(1)<"+"/script>";
$("#iframe").contents().find("body").append(scriptTag);

6
只需转义斜杠:var scriptTag = "<script>alert(1)<\\/script>"; - http://jsfiddle.net/tLHn5/ - keaukraine
@keaukraine 这是一种很棒的技巧,我以前从未见过,因为不需要转义正斜杠。不过我在想这种行为是否被规定了。 - Ruan Mendes
转义斜杠完美地解决了问题。我将脚本标签直接放入src中,没有任何问题。 - Edward

8
function putScriptInIframes(script, scriptId) {

   var $iframes = $('iframe');
   $iframes.each(function () {
        var thisDoc = this.contentWindow.document;
        if ( ! thisDoc.getElementById(scriptID)) {
            var scriptObj = thisDoc.createElement("script");
            scriptObj.type = "text/javascript";
            scriptObj.id = scriptId;
            scriptObj.innerHTML = script;
            thisDoc.body.appendChild(scriptObj);
        }
    });
}

这是我能让它工作的最简单方法。

5
var script = "alert('hello world');";
$('#iframe').contents().find('body').append($('<script>').html(script))

Fiddle中工作


1
能否解释一下它们的区别?我知道它可以工作,但不明白为什么。 - Ruan Mendes
我认为这个区别与jQuery中text()方法和html()方法的区别相同。如果你附加一个字符串,它可能不会被视为HTML。 - Neil S
1
@JuanMendes 原因不是很清楚为什么原始代码无法工作,但猜测代码片段位于<script>元素中,在其中提到</script>将关闭该元素而不是保留为String值。这避免了提及它。 - Jonathan Lonowski
@JonathanLonowski,没错,我在你发表这条评论的同时添加了一个解释答案。 - Ruan Mendes
如果你需要加载完整的 JavaScript 文件,你应该使用 getScript() 将它加载到框架中。 - Neil S
显示剩余4条评论

4

你需要转义/script。它出现了。

例如像Google Analytics一样操作。

 $("#iframe").contents().find("body").append(decodeURI("**%3Cscript%3E** alert(2)  **%3C/script%3E**")); 

用这些转义字符替换script/script

希望对您有所帮助。


这个可以运行,但是在我的脑海中仍然不合理,请添加解释。 - Ruan Mendes
嗯...我想jQuery正在使用脚本进行某种验证。 - Bruno Braga
不是 jQuery 的问题,我找到了问题所在,正在发布答案。 - Ruan Mendes

2

由于 iframe 运行在自己的 window 中,您还需要注入 jquery.js 文件的导入。

<script type="text/javascript" src="/jquery/jquery-ui-1.9.1.custom.js"></script>

编辑:我对此进行了一些操作,以下是我的结果。

HTML

<iframe id="frame"></iframe>

JS

$("#frame").attr(
   "src", "data:text/html;charset=utf-8," + 
   "<html>" + 
   "<style>.red {color: red}</style>" + 
   "<div class=\"test\">Test</test>" + 
   "<script src=\"http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js\"><" + "/script>" +    
   "<script>$(function(){ $(\".test\").addClass(\"red\")});<" + "/script>" +         
   "</html>"
);

这个可以工作,可以在这里看到 http://jsfiddle.net/WsCxj/

所以有几点需要注意:

  1. 我将整个内容作为一个字符串传递。您必须在前面添加 data:text/html;charset=utf-8,,然后将字符串设置为 iframe 的 src。

  2. 我使用绝对路径添加了 jquery.js 文件 - 这似乎很重要,可能是因为框架本身没有路径,因为它的内容是动态生成的。

  3. 我像这样分割了脚本结束标记 <" + "/script>,因为至少 Firefox 尝试在此时结束实际脚本。更干净的方法可能是将 js 作为完全独立的文件。


嗯...你尝试过将整个内容构建为一个字符串,然后将其设置为iframe的src属性吗? - ced-b
l="<script"+" src"+"=""+" rel = "nofollow noreferrer">http://code.jquery.com/jquery-1.9.1.js\">"+"<"+"/"+"script>"; $('#iframe_id').contents().find('body').append(l); - Gandalf
@Gandalf,请查看修改,它可以正常工作。您可能可以采用jQuery方法使其工作,但通常使用字符串构建HTML比在jQuery中执行更快。 - ced-b
在IE9中,iframe显示“无法显示网页”的错误。有什么原因? - Gandalf
IE可能需要一些特殊处理,请查看此线程:https://dev59.com/OmQn5IYBdhLWcg3w36XV - ced-b

1
你不需要添加script标签来执行JavaScript,你可以使用eval函数并应用iframe上下文...
使用eval
function initFrame (code){

    eval (code);

}

initFrame.apply ($('#iframe').contents(),[js_code]);

没有eval

var initFrame = new Function(js_code);


initFrame.apply ($('#iframe').contents(),[]);

使用 new Function 本质上与 eval 相同。在另一个框架的上下文中运行函数可能会出现问题,并且很难进行调试,因为两个上下文中的全局对象是不同的... - Ruan Mendes
eval无法接收返回语句,函数也不能解析像(5)这样的值,eval和new Function是不同的。 - Luan Castro
是的,它们略有不同,但在您的情况下完全没有关系。 new Function 在幕后仍然执行 eval。因此,避免在 new Function 中使用 eval 并没有任何好处。 eval 可能不允许使用返回语句,但它会返回最后一个表达式的值。 - Ruan Mendes
如果js_code的内容是核心JavaScript,这似乎是有效的。如果js_code的内容是jQuery片段,这似乎就不起作用了。有什么建议吗? - Gandalf

-1

这个对我有用,将以下代码粘贴到页面中,该页面位于iframe中,而不是父页面:

window.myFunction = function(args) {
   alert("script from iframe");
}

现在添加以下代码来调用上述函数:

var iframe = document.getElementById("iframeId");
iframe.contentWindow.myFunction(args);

-2

使用JS间隔函数设置ajax刷新,以获取存储在文件/会话等中的任何数据,如何?

这肯定不是最轻量级的模式,它涉及一点点PHP,但可以完成工作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接