ChatGPT解决这个技术问题 Extra ChatGPT

如何使用 JavaScript/jQuery 访问 iframe 的内容?

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

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

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

但是,这似乎不起作用。稍微检查一下,我发现 frames['nameOfMyIframe'] 中的变量是 undefined,除非我等待一段时间让 iframe 加载。但是,当 iframe 加载时,变量不可访问(我得到 permission denied 类型的错误)。

有谁知道解决这个问题的方法?

iFrame 包含什么 - 它的 src 是否设置为另一个域?
如果是其他域,是否还有办法访问其内容或注册事件
不,因为那将是跨站点脚本,出于安全原因,这是被禁止的。我的解决方案是使用代理:通过我自己的站点逐字提供 IFRAME 中的 HTML,因此从浏览器的角度来看,它不再是跨站点的。
iframe 元素上使用 .contentWindow.document 比使用 .document 更适合跨浏览器。我会建议上面的更改。
一种方法是 chrome 扩展

R
RevanthKrishnaKumar V.

如果 <iframe> 来自同一域,则可以轻松访问元素

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

Reference


了解同源策略很好,但这是 OP 想要的答案。为什么另一个答案被选为正确答案?
O
Onur Bebin

我认为您所做的事情受 same origin policy 的约束。这应该是您收到 permission denied type 错误的原因。


@Tracker1:您能否建议任何框架/api/设计模式来实现此代理解决方案。示例或教程等的任何链接?我试图搜索但找不到任何东西。
N
Narendra Jadhav

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

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

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

b
brasofilo

如果 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 编辑外部页面而不拒绝访问等的示例...


当然,由于您的服务器获取的是远程页面而不是用户的浏览器,因此不会向远程页面发送任何 cookie。 YMMV。
@Mark:如果您使用 curl 扩展程序实现它,您可以轻松发送 cookie、发布的数据、HTTP 标头等等。 php.net/manual/en/book.curl.php
@geon:但浏览器不会将外部域的 cookie 发送到您的 PHP 脚本
@Mark:据浏览器所知,不涉及外域。浏览器将与您的服务器(包括 cookie、发布的数据和标头)对话,而后者又会与外部域对话。 (除非它使用诸如通过图像设置/读取的 cookie 等技巧,这可以通过解析 HTML 并通过 PHP 路由它们来修复。)
@geon 标记的意思是浏览器不会将任何用于外部域的 cookie 发送到您的域(例如,它不会将 cookie 从 bank.com 发送到 mydomain.com),因此用户将看到没有 cookie 的页面(即注销)
R
RevanthKrishnaKumar V.

利用

iframe.contentWindow.document

代替

iframe.contentDocument

很好的答案。这适用于其他域中的 iFrame。我在 Safari 和 Firefox 的控制台中尝试了这个。
我相信如果您从控制台执行此操作,它仅适用于其他域。不允许从脚本访问。
这应该是公认的答案。当 iframe 来自不同的域时,挽救了我的生命和工作;尽管如前所述,仅在控制台中。
对我来说 iframe.contentWindow.document 并不总是有效。当它没有时,我发现 $(elem).contents().get(0) 确实
您可以在浏览器控制台中选择“根文档”。当您选择“顶部”时,它将不起作用,作为跨域访问。如果您选择以 iframe 文件的名义访问,它当然会给您访问权限。仅仅因为您不是浏览器,而是浏览器的所有者。
z
zupa

我发现这种方式更清洁:

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

救了我的屁股 - 我快疯了,使用“$(”#iframe“).contents().find()”由于某种原因不起作用......两行同样的事情。不知道为什么,但它有效。
A
Andreas Grech

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

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

以上将解决“尚未加载”的问题,但关于权限,如果您在 iframe 中加载来自不同域的页面,由于安全限制,您将无法访问它。


这是一个好主意,事实上我正在尝试就像你回答的那样。但是,它不能解决被拒绝的权限(它确实解决了我在开始访问 iframe 之前必须等待的问题)
实际上......没关系,即使这样做似乎仍然需要等待。
就绪功能有效。但是,它似乎并没有等待 iframe 的内容完成加载——即使在 iframe 本身的内容上调用时,它也只针对父文档。我想这也是因为同源政策。
关于此代码的几点注意事项:您应该使用 iframe.contentDocument 而不是 .document,并且应该使用 .load() 而不是 .ready() 以避免等待。 (不完美,但更好)
S
Sevle

您可以使用 window.postMessage 在页面和他的 iframe 之间调用一个函数(跨域与否)。

Documentation

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>

E
Evgeny Karpov

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

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

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

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


K
Khb

您是否尝试过经典的,使用 jQuery 的内置准备功能等待加载完成?

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

ķ


是的。 ready 函数在加载主框架时开始执行——而不是在加载 iframe 时。不过,等待似乎只是问题的一小部分。我认为这与跨域安全有关。
Z
Zisu

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

我与您分享我的代码,请运行此代码检查控制台。我在控制台打印图像 src。有四个 iframe ,两个 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错误:权限被拒绝访问属性'document'

...irstChild)},contents:function(a){return 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>

D
Dominique Fortin

为了更加稳健:

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();
  ...
}
...

J
Jeff Davis

我最终在这里寻找没有 jquery 的 iframe 的内容,所以对于其他寻找它的人来说,就是这样:

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

A
Ahsan Horani

此解决方案与 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;
}

这将如何工作?如果您将 $customJS 字符串附加到 $content,您不会在关闭 html 标记(外部域的)之后拥有脚本元素吗?
I
Imran Zahoor

如果下面的代码不起作用

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

这是使其工作的可靠方法:

$(document).ready(function(){ 
  setTimeout(
    function () {
      $("#iFrame").contents().find("#someDiv").removeClass("hidden");
    },
    300
  );
});

这样,脚本将在 300 毫秒后运行,因此它将获得足够的时间来加载 iFrame,然后代码将开始执行。有时 iFrame 不会加载并且脚本会尝试在它之前执行。 300ms 可以根据您的需要调整为其他任何内容。