jQuery / JavaScript: truy cập nội dung của iframe


792

Tôi muốn thao tác HTML bên trong iframe bằng jQuery.

Tôi nghĩ rằng tôi có thể làm điều này bằng cách đặt bối cảnh của hàm jQuery thành tài liệu của iframe, đại loại như:

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

Tuy nhiên điều này dường như không hoạt động. Một chút kiểm tra cho tôi thấy rằng các biến trong frames['nameOfMyIframe']undefinedtrừ khi tôi đợi một lúc để iframe tải. Tuy nhiên, khi iframe tải các biến không thể truy cập (tôi gặp permission deniedlỗi -type).

Có ai biết về một công việc xung quanh này?


3
IFrame chứa gì - src của nó được đặt sang tên miền khác?
James

nếu đó là một tên miền khác, vẫn có cách để truy cập nội dung của nó hoặc đăng ký một sự kiện
adardesign

34
Không, bởi vì đó sẽ là kịch bản chéo trang, bị cấm vì lý do bảo mật. Giải pháp của tôi là sử dụng proxy: cung cấp HTML trong nguyên văn IFRAME thông qua trang web của riêng tôi để nó không còn là trang web chéo giữa các quan điểm của trình duyệt.
rebierpost

Đó là sử dụng .contentWindow.documentnhiều trình duyệt chéo hơn là .documenttrên iframephần tử. Tôi sẽ đề nghị thay đổi ở trên.
Alan H.

1
một cách là tiện ích mở rộng chrome
Muhammad Umer

Câu trả lời:


384

Tôi nghĩ những gì bạn đang làm là tuân theo chính sách xuất xứ tương tự . Đây phải là lý do tại sao bạn nhận được quyền loại bỏ lỗi loại .


6
@Pacerier Đặt cược tốt nhất là ủy quyền nội dung của iframe trên trang web của bạn, nếu bạn có thể ...
Tracker1

10
@ Tracker1: Bạn có thể đề xuất bất kỳ mẫu khung / api / thiết kế nào để triển khai giải pháp proxy này không. Bất kỳ liên kết đến ví dụ hoặc hướng dẫn vv? Tôi đã cố gắng tìm kiếm nhưng không thể tìm thấy bất kỳ.
Umer Hayat

3
Trong trường hợp này, anh ta có nghĩa là sử dụng máy chủ http đang phục vụ trang tên miền của bạn làm proxy - yêu cầu nội dung từ trang web của bên thứ 3 và chuyển tiếp nó trong phản hồi http cho khách hàng. Như bạn có thể đoán, nó nhanh chóng tác động đến khả năng phản hồi của trang web của bạn vì các yêu cầu song song trước đó được thực hiện nối tiếp với máy chủ của bạn như một nút cổ chai tiềm năng.
rutherford

1
@Pacerier Có khả năng bất kỳ phương thức nào trong câu trả lời được chấp nhận ở đây: stackoverflow.com/questions/3076414/ mẹo hoặc những người khác (như sử dụng tên miền của riêng bạn làm proxy), tùy thuộc vào những gì bạn muốn đạt được.
Đánh dấu Amery

4
Đối với bản ghi, tôi chỉ thiết lập một cái gì đó tương tự: nếu bạn không muốn kết quả cực kỳ chậm, chỉ cần thiết lập máy chủ web của bạn để định tuyến lại trực tiếp các yêu cầu tài sản (CSS / JS / hình ảnh) đến trang web gốc, vì vậy proxy của bạn chỉ quản lý các yêu cầu HTML. Tôi đang duyệt một trang web xa dưới localhost ngay bây giờ và nó hoàn toàn minh bạch :)
neemzy

985

Nếu <iframe>là từ cùng một tên miền, các yếu tố có thể dễ dàng truy cập như

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

Tài liệu tham khảo


157
Biết về chính sách xuất xứ tương tự là rất tốt nhưng đây là câu trả lời mà OP muốn. Tại sao câu trả lời khác được chọn là câu trả lời đúng?
Jason Swett

2
Bạn phải sử dụng proxy để lấy HTML trong nguồn gốc của mình. Ví dụ: johnchapman.name/ Từ
mhenry1384

7
@JasonSwett, tôi đoán rằng vấn đề của OP thực sự là same origin policy, trong trường hợp này câu trả lời này không phải là một giải pháp cho anh ta.
ANeves

3
@fizzbuzz Sau đó, bạn nhận được IFrame giống như cách bạn nhận bất kỳ nội dung không có id nào khác với jQuery: bạn chọn thẻ <IFrame> phù hợp với CSS, sử dụng tên lớp và giá trị thuộc tính để thu hẹp nếu cần.
Auspex

2
Không có phương pháp nào gọi là nội dung cho iframe.
Renan

88

Bạn có thể sử dụng .contents()phương pháp của jQuery.

Các .contents()phương pháp cũng có thể được sử dụng để có được những tài liệu nội dung của một khung nội tuyến, nếu iframe là trên cùng một tên miền như trang chính.

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

2
Tôi cần phải lấy nội dung khung hình i để không thiết lập cơ thể ..... Khi tôi làm như trên, nó không hoạt động luôn trả về Cơ thể trống rỗng
George Hanna

3
@DarkoZ Um, thực sự câu trả lời này đã xuất hiện đầu tiên, vì vậy nếu có bất cứ điều gì, câu trả lời khác là bản sao
michaelpri

@DarkoZ: để lại nhận xét ban đầu không làm tôi xấu hổ về bạn, nhưng tôi đã lãng phí như 30 giây để cố gắng hiểu một vấn đề không phải vậy :) Vì vậy, loại bỏ toàn bộ cuộc thảo luận về câu trả lời đạo văn này có thể là tốt nhất.
Dan Dascalescu

bình luận loại bỏ để tránh nhầm lẫn. xin lỗi
Darko Z

43

Nếu ifrc src là từ một tên miền khác, bạn vẫn có thể làm điều đó. Bạn cần đọc trang bên ngoài vào PHP và lặp lại từ miền của bạn. Như thế này:

iframe_page.php

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

    $domain = file_get_contents($URL);

    echo $domain;
?>

Sau đó, một cái gì đó như thế này:

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>

Trên đây là một ví dụ về cách chỉnh sửa trang bên ngoài thông qua iframe mà không có quyền truy cập bị từ chối, v.v ...


12
Tất nhiên, vì máy chủ của bạn đang nhận trang từ xa chứ không phải trình duyệt của người dùng, nên sẽ không có cookie nào được gửi đến trang từ xa. YMMV.
Đánh dấu Fowler

1
@Mark: Bạn có thể dễ dàng gửi cookie, dữ liệu đã đăng, tiêu đề HTTP và không có gì nếu bạn triển khai nó với tiện ích mở rộng. php.net/manual/en/book.curl.php
geon

2
@geon: nhưng trình duyệt sẽ không gửi cookie cho tên miền nước ngoài tới tập lệnh PHP của bạn
ysth

6
@basysmith Hãy chú ý: có một lý do tại sao sự same origin policytồn tại và đề xuất của câu trả lời này không tránh khỏi nó.
ANeves

1
nó là bất hợp pháp trong bất kỳ cách nào để làm điều này?
Tallboy

32

Tôi thấy cách này sạch hơn:

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

Cứu lấy mông của tôi - Tôi đã phát điên, sử dụng "$ (" # iframe "). Nội dung (). Find ()" không hoạt động vì một số lý do ... điều tương tự trên hai dòng đã làm. Dunno tại sao, nhưng nó hoạt động.
neminem

30

Sử dụng

iframe.contentWindow.document

thay vì

iframe.contentDocument

Câu trả lời chính xác. Điều này hoạt động cho iFrames trong các lĩnh vực khác. Tôi đã thử điều này trong bảng điều khiển trên Safari và Firefox.
Aneil Mallavarapu

12
Tôi tin rằng nó sẽ chỉ hoạt động cho các miền khác nếu bạn đang làm điều đó từ bảng điều khiển. Từ một kịch bản, truy cập sẽ không được phép.
yincrash

Đây phải là câu trả lời được chấp nhận. Đã cứu mạng tôi và hoạt động khi iframe đến từ một miền khác; Mặc dù như đã đề cập, chỉ trong giao diện điều khiển.
lửa lụa

đối với tôi iframe.contentWindow.document không phải lúc nào cũng hoạt động. và khi tôi không thấy rằng $ (elem) .contents (). get (0) hiện
elewinso

bạn có thể chọn "tài liệu gốc" trong bảng điều khiển trình duyệt. Khi bạn chọn "trên cùng", nó sẽ không hoạt động, như một truy cập nguồn gốc chéo. Nếu bạn chọn truy cập thay mặt cho tài liệu iframe, tất nhiên nó sẽ cấp cho bạn quyền truy cập. Chỉ vì bạn không phải là trình duyệt, mà là chủ sở hữu trình duyệt.
Sergei Kovalenko

26

Bạn cần đính kèm một sự kiện vào trình xử lý tải của iframe và thực thi js trong đó, để bạn chắc chắn rằng iframe đã tải xong trước khi truy cập nó.

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

Ở trên sẽ giải quyết vấn đề 'chưa được tải', nhưng liên quan đến các quyền, nếu bạn đang tải một trang trong iframe từ một tên miền khác, bạn sẽ không thể truy cập được do hạn chế bảo mật.


Đây là một ý tưởng tốt, trên thực tế tôi đã thử nó như bạn đã trả lời. Tuy nhiên, nó không hoạt động xung quanh quyền bị từ chối (nó giải quyết việc tôi phải đợi trước khi bắt đầu truy cập vào nội dung iframe)
rz.

thực sự ... không có gì, có vẻ như sự chờ đợi vẫn được yêu cầu ngay cả khi làm điều này.
rz.

Các chức năng sẵn sàng hoạt động. Tuy nhiên, dường như không chờ nội dung của iframe hoàn tất tải - chỉ dành cho tài liệu gốc ngay cả khi được gọi trên chính nội dung của iframe. Tôi tưởng tượng nó cũng là do chính sách xuất xứ tương tự.
rz.

3
Một vài lưu ý về mã này: bạn nên sử dụng iframe.contentDocument thay vì .document và bạn nên sử dụng .load () thay vì. Yet () để tránh sự chờ đợi. (Không hoàn hảo, nhưng tốt hơn)
Rodrigo Queiro

21

Bạn có thể sử dụng window.postMessage để gọi một hàm giữa trang và iframe của anh ấy (tên miền chéo hoặc không).

Tài liệu

trang.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

Tôi thích sử dụng các biến thể khác để truy cập. Từ cha mẹ, bạn có thể có quyền truy cập vào biến trong iframe con. $cũng là một biến và bạn có thể nhận quyền truy cập vào cuộc gọi chỉ của nó window.iframe_id.$

Ví dụ, window.view.$('div').hide() - ẩn tất cả các div trong iframe với id 'view'

Nhưng, nó không hoạt động trong FF. Để tương thích tốt hơn, bạn nên sử dụng

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


2

Bạn đã thử cách cổ điển, chờ tải xong để sử dụng hàm sẵn sàng dựng sẵn của jQuery chưa?

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

K


2
Đúng. Hàm sẵn sàng bắt đầu thực thi khi khung chính được tải - không phải khi khung iframe được tải. Sự chờ đợi dường như là một phần nhỏ của vấn đề. Tôi nghĩ rằng nó phải làm với bảo mật tên miền chéo.
rz.

2

Tôi tạo một mã mẫu. Giờ đây, bạn có thể dễ dàng hiểu từ các tên miền khác nhau mà bạn không thể truy cập nội dung của iframe .. Cùng một tên miền chúng ta có thể truy cập nội dung iframe

Tôi chia sẻ cho bạn mã của tôi, Vui lòng chạy mã này kiểm tra bàn điều khiển. Tôi in hình ảnh src tại bàn điều khiển. Có bốn iframe, hai iframe đến từ cùng một tên miền và hai iframe khác (bên thứ ba). Bạn có thể thấy hai hình ảnh 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 ) tại bảng điều khiển và cũng có thể thấy hai lỗi cấp phép (2 Lỗi: Quyền bị từ chối truy cập tài liệu ' '

... irstChild)}, nội dung: function (a) {return m.nodeName (a, "iframe")? a.contentDocument ...

) đến từ iframe của bên thứ ba.

<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

Tôi đã kết thúc ở đây để tìm kiếm nội dung của iframe mà không cần jquery, vì vậy đối với bất kỳ ai khác đang tìm kiếm điều đó, nó chỉ là thế này:

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

1

Giải pháp này hoạt động tương tự như iFrame. Tôi đã tạo một tập lệnh PHP có thể lấy tất cả nội dung từ trang web khác và phần quan trọng nhất là bạn có thể dễ dàng áp dụng jQuery tùy chỉnh của mình cho nội dung bên ngoài đó. Vui lòng tham khảo tập lệnh sau có thể lấy tất cả nội dung từ trang web khác và sau đó bạn cũng có thể áp dụng jQuery / JS cusom của mình. Nội dung này có thể được sử dụng ở bất cứ đâu, bên trong bất kỳ yếu tố hoặc bất kỳ trang nào.

<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

Để mạnh mẽ hơn nữa:

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();
  ...
}
...
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.