jQuery / JavaScript:访问iframe的内容


791

我想使用jQuery在iframe中操纵HTML。

我认为我可以通过将jQuery函数的上下文设置为iframe的文档来做到这一点,例如:

$(function(){ //document ready
    $('some selector', frames['nameOfMyIframe'].document).doStuff()
});

但是,这似乎不起作用。一点检查就可以看出,除非等待iframe加载,否则其中的变量frames['nameOfMyIframe']undefined。但是,在iframe加载时,变量不可访问(我收到permission denied-type错误)。

有人知道解决方法吗?


3
iFrame包含什么-它的src是否设置为另一个域?
詹姆斯,

如果它是另一个域,是否仍然可以访问其内容或注册事件
adardesign's

34
不可以,因为那将是跨站点脚本,出于安全原因而被禁止。我的解决方案是使用代理:通过我自己的网站逐字记录IFRAME中的HTML,因此不再从浏览器的角度跨网站。
reinierpost

.contentWindow.document比元素.document上使用的跨浏览器更多iframe。我建议上面的更改。
艾伦·H。

1
一种方法是chrome扩展程序
Muhammad Umer

Answers:


383

我认为您在做的事情要遵循相同的原产地政策。这应该是您收到权限拒绝类型错误的原因。


6
@Pacerier最好的选择是在您的站点上代理iframe的内容,如果可以...
Tracker1,2012年

10
@ Tracker1:您能建议任何框架/ api /设计模式来实现此代理解决方案吗?有链接到示例或教程等吗?我试图搜索,但找不到任何东西。
Umer Hayat 2012年

3
在这种情况下,他的意思是使用为您的域页面提供服务的http服务器作为代理-从第3方网站请求内容并将其在http响应中转发给客户端。您可能会猜到,它会很快影响站点的响应能力,因为以前的并行请求是与服务器串联执行的,这是潜在的瓶颈。
卢瑟福2013年

1
@Pacerier可能在这里接受答案中的任何方法:stackoverflow.com/questions/3076414/…或其他(例如,使用您自己的域作为代理),具体取决于您要实现的目标。
Mark Amery

4
作为记录,我只是设置了类似的内容:如果您不希望结果变慢得令人难以置信,则只需将您的Web服务器设置为将资产请求(CSS / JS /图像)直接重新路由到原始网站即可,因此您的代理仅管理HTML请求。我现在正在本地主机下浏览一个远程站点,它是完全透明的:)
neemzy

985

如果<iframe>来自同一域,则可以很容易地访问元素

$("#iFrame").contents().find("#someDiv").removeClass("hidden");

参考


157
知道相同的原产地政策非常好,但这就是OP想要的答案。为什么其他答案被选为正确答案?
杰森·斯威特

2
您必须使用代理来获取源HTML。例如,johnchapman.name /…
mhenry1384

7
@JasonSwett,我的猜测是OP的问题确实是same origin policy,在这种情况下,此答案不是他的解决方案。
ANeves 2011年

3
@fizzbuzz然后,您将以与获取jQuery其他任何无id内容相同的方式获取IFrame:使用CSS选择适当的<IFrame>标记,并在必要时使用类名和属性值将其范围缩小。
Auspex

2
iframe 没有称为内容的方法。
Renan

88

您可以使用.contents()jQuery的方法。

.contents()如果iframe与主页位于同一域中,则该方法还可用于获取iframe的内容文档。

$(document).ready(function(){
    $('#frameID').load(function(){
        $('#frameID').contents().find('body').html('Hey, i`ve changed content of <body>! Yay!!!');
    });
});

2
我需要获取i框架内容,而不要设置主体.....当我执行上述操作时,它总是不起作用,总是返回空的主体
George Hanna 2012年

3
@DarkoZ嗯,实际上这个答案是第一位的,因此,如果有的话,另一个答案就是副本
michaelpri

@DarkoZ:留下原始评论并没有让我感到羞耻,但是我确实花了30秒钟试图理解一个非问题:),所以最好删除整个关于窃性答案的讨论。
Dan Dascalescu 2015年

删除注释以防止混淆。道歉。
Darko Z 2015年

43

如果iframe src来自其他域,您仍然可以这样做。您需要将外部页面读入PHP并从您的域中回显它。像这样:

iframe_page.php

<?php
    $URL = "http://external.com";

    $domain = file_get_contents($URL);

    echo $domain;
?>

然后是这样的:

display_page.html

<html>
<head>
  <title>Test</title>
 </head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.1/jquery.min.js"></script>

<script>

$(document).ready(function(){   
    cleanit = setInterval ( "cleaning()", 500 );
});

function cleaning(){
    if($('#frametest').contents().find('.selector').html() == "somthing"){
        clearInterval(cleanit);
        $('#selector').contents().find('.Link').html('ideate tech');
    }
}

</script>

<body>
<iframe name="frametest" id="frametest" src="http://yourdomain.com/iframe_page.php" ></iframe>
</body>
</html>

上面的示例说明了如何通过iframe编辑外部页面而不会导致访问被拒绝等。


12
当然,由于您的服务器正在获取远程页面而不是用户的浏览器,因此不会将cookie发送到该远程页面。YMMV。
马克·福勒

1
@Mark:如果您使用curl扩展实现它,则可以轻松地发送cookie,发布的数据,HTTP标头等等。php.net/manual/en/book.curl.php

2
@geon:但是浏览器不会将外部域的Cookie发送到您的PHP脚本
ysth 2011年

6
@basysmith请注意:存在之所以存在是有原因的same origin policy,而这个答案的提议就不能幸免。
ANeves 2011年

1
这样做是非法的吗?
Tallboy

32

我发现这种方式更清洁:

var $iframe = $("#iframeID").contents();
$iframe.find('selector');

救了我的屁股-我快要疯了,使用“ $(”#iframe“)。contents()。find()”由于某种原因无法正常工作,两行都做同样的事情。Dunno为什么,但是它有效。
neminem

30

采用

iframe.contentWindow.document

代替

iframe.contentDocument

好答案。这适用于其他域中的iFrame。我在Safari和Firefox的控制台中尝试过此操作。
Aneil Mallavarapu 2010年

12
我相信,如果您从控制台执行此操作,则它仅适用于其他域。从脚本中,将不允许访问。
yincrash 2011年

这应该是公认的答案。当iframe来自其他域时,可以挽救我的生命并工作;尽管如上所述,但仅在控制台中。
Silkfire

对我来说,iframe.contentWindow.document并不总是有效。而当我没有找到$(elem).contents()。get(0)时
elewinso

您可以在浏览器控制台中选择“根文档”。当您选择“顶部”时,它不能用作跨域访问。如果您选择代表iframe文档进行访问,那么它将为您提供访问权限。只是因为您不是浏览器,而是浏览器所有者。
谢尔盖·科瓦连科

26

您需要将事件附加到iframe的onload处理程序,并在其中执行js,以便在访问iframe之前确保iframe已完成加载。

$().ready(function () {
    $("#iframeID").ready(function () { //The function below executes once the iframe has finished loading
        $('some selector', frames['nameOfMyIframe'].document).doStuff();
    });
};

上面的方法可以解决“尚未加载”的问题,但是在权限方面,如果您要在iframe中加载来自其他域的页面,则由于安全限制,您将无法访问该页面。


这是一个好主意,实际上我正按照您的回答进行尝试。但是,它不能绕开被拒绝的权限(它确实解决了我必须等待才能开始访问iframe内容的问题)
rz。

实际上...没关系,即使这样做,似乎仍然需要等待。
rz。

准备功能起作用。但是,似乎它并不等待iframe的内容完成加载-仅针对父文档,即使在iframe本身的内容上调用时也是如此。我想这也是由于相同的原产地政策。
rz。

3
关于此代码的几点注意事项:应该使用iframe.contentDocument而不是.document,并且应该使用.load()而不是.ready()以避免等待。(不完美,但是更好)
Rodrigo Queiro

21

您可以使用window.postMessage在页面与其iframe之间(无论是否跨域)调用函数。

文献资料

page.html

<!DOCTYPE html>
<html>
<head>
    <title>Page with an iframe</title>
    <meta charset="UTF-8" />
    <script src="http://code.jquery.com/jquery-1.10.2.min.js"></script>
    <script>
    var Page = {
        id:'page',
        variable:'This is the page.'
    };

    $(window).on('message', function(e) {
        var event = e.originalEvent;
        if(window.console) {
            console.log(event);
        }
        alert(event.origin + '\n' + event.data);
    });
    function iframeReady(iframe) {
        if(iframe.contentWindow.postMessage) {
            iframe.contentWindow.postMessage('Hello ' + Page.id, '*');
        }
    }
    </script>
</head>
<body>
    <h1>Page with an iframe</h1>
    <iframe src="iframe.html" onload="iframeReady(this);"></iframe>
</body>
</html>

iframe.html

<!DOCTYPE html>
<html>
<head>
    <title>iframe</title>
    <meta charset="UTF-8" />
    <script src="http://code.jquery.com/jquery-1.10.2.min.js"></script>
    <script>
    var Page = {
        id:'iframe',
        variable:'The iframe.'
    };

    $(window).on('message', function(e) {
        var event = e.originalEvent;
        if(window.console) {
            console.log(event);
        }
        alert(event.origin + '\n' + event.data);
    });
    $(window).on('load', function() {
        if(window.parent.postMessage) {
            window.parent.postMessage('Hello ' + Page.id, '*');
        }
    });
    </script>
</head>
<body>
    <h1>iframe</h1>
    <p>It's the iframe.</p>
</body>
</html>

4

我更喜欢使用其他变体进行访问。您可以从父级访问子级iframe中的变量。 $也是一个变量,您可以访问它的just调用 window.iframe_id.$

例如,window.view.$('div').hide()-在ID为'view'的iframe中隐藏所有div

但是,它在FF中不起作用。为了获得更好的兼容性,您应该使用

$('#iframe_id')[0].contentWindow.$


2

您是否尝试过经典,等待使用jQuery的内置ready函数完成加载?

$(document).ready(function() {
    $('some selector', frames['nameOfMyIframe'].document).doStuff()
} );

ķ


2
是。准备功能在加载主机时开始执行-而不是在加载iframe时执行。不过,等待似乎只是问题的一小部分。我认为这与跨域安全性有关。
rz。

2

我创建一个示例代码。现在,您可以轻松地从其他域中了解您无法访问iframe的内容。在同一域中,我们可以访问iframe内容

我与您共享我的代码,请运行此代码检查控制台。我在控制台上打印图像src。有四个iframe,两个来自同一个域,另一个来自其他域(第三方)。您可以看到两个图像src(https://www.google.com/logos/doodles/2015/googles-new-logo -5078286822539264.3-hp2x.gif

在控制台https://www.google.com/logos/doodles/2015/arbor-day-2015-brazil-5154560611975168-hp2x.gif),还可以看到两个权限错误(2错误:拒绝访问“文档”属性的权限'

... irstChild)},内容:function(a){返回m.nodeName(a,“ iframe”)?a.contentDocument ...

),它来自第三方iframe。

<body id="page-top" data-spy="scroll" data-target=".navbar-fixed-top">
<p>iframe from same domain</p>
  <iframe frameborder="0" scrolling="no" width="500" height="500"
   src="iframe.html" name="imgbox" class="iView">

</iframe>
<p>iframe from same domain</p>
<iframe frameborder="0" scrolling="no" width="500" height="500"
   src="iframe2.html" name="imgbox" class="iView1">

</iframe>
<p>iframe from different  domain</p>
 <iframe frameborder="0" scrolling="no" width="500" height="500"
   src="https://www.google.com/logos/doodles/2015/googles-new-logo-5078286822539264.3-hp2x.gif" name="imgbox" class="iView2">

</iframe>

<p>iframe from different  domain</p>
 <iframe frameborder="0" scrolling="no" width="500" height="500"
   src="http://d1rmo5dfr7fx8e.cloudfront.net/" name="imgbox" class="iView3">

</iframe>

<script type='text/javascript'>


$(document).ready(function(){
    setTimeout(function(){


        var src = $('.iView').contents().find(".shrinkToFit").attr('src');
    console.log(src);
         }, 2000);


    setTimeout(function(){


        var src = $('.iView1').contents().find(".shrinkToFit").attr('src');
    console.log(src);
         }, 3000);


    setTimeout(function(){


        var src = $('.iView2').contents().find(".shrinkToFit").attr('src');
    console.log(src);
         }, 3000);

         setTimeout(function(){


        var src = $('.iView3').contents().find("img").attr('src');
    console.log(src);
         }, 3000);


    })


</script>
</body>

1

我最终在这里寻找了没有jquery的iframe内容,因此对于其他正在寻找的人来说,就是这样:

document.querySelector('iframe[name=iframename]').contentDocument

1

此解决方案与iFrame相同。我创建了一个PHP脚本,可以从其他网站获取所有内容,最重要的部分是您可以轻松地将自定义jQuery应用于该外部内容。请参考以下脚本,该脚本可以从其他网站获取所有内容,然后您也可以应用自定义jQuery / JS。此内容可以在任何元素或任何页面内的任何位置使用。

<div id='myframe'>

  <?php 
   /* 
    Use below function to display final HTML inside this div
   */

   //Display Frame
   echo displayFrame(); 
  ?>

</div>

<?php

/* 
  Function to display frame from another domain 
*/

function displayFrame()
{
  $webUrl = 'http://[external-web-domain.com]/';

  //Get HTML from the URL
  $content = file_get_contents($webUrl);

  //Add custom JS to returned HTML content
  $customJS = "
  <script>

      /* Here I am writing a sample jQuery to hide the navigation menu
         You can write your own jQuery for this content
      */
    //Hide Navigation bar
    jQuery(\".navbar.navbar-default\").hide();

  </script>";

  //Append Custom JS with HTML
  $html = $content . $customJS;

  //Return customized HTML
  return $html;
}

0

为了更强大:

function getIframeWindow(iframe_object) {
  var doc;

  if (iframe_object.contentWindow) {
    return iframe_object.contentWindow;
  }

  if (iframe_object.window) {
    return iframe_object.window;
  } 

  if (!doc && iframe_object.contentDocument) {
    doc = iframe_object.contentDocument;
  } 

  if (!doc && iframe_object.document) {
    doc = iframe_object.document;
  }

  if (doc && doc.defaultView) {
   return doc.defaultView;
  }

  if (doc && doc.parentWindow) {
    return doc.parentWindow;
  }

  return undefined;
}

...
var frame_win = getIframeWindow( frames['nameOfMyIframe'] );

if (frame_win) {
  $(frame_win.contentDocument || frame_win.document).find('some selector').doStuff();
  ...
}
...
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.