jQuery / JavaScript: mengakses konten iframe

792

Saya ingin memanipulasi HTML di dalam iframe menggunakan jQuery.

Saya pikir saya akan bisa melakukan ini dengan mengatur konteks fungsi jQuery menjadi dokumen iframe, seperti:

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

Namun sepertinya ini tidak berhasil. Sedikit pemeriksaan menunjukkan bahwa variabel dalam frames['nameOfMyIframe']adalah undefinedkecuali aku menunggu beberapa saat untuk iframe ke beban. Namun, ketika iframe memuat variabel tidak dapat diakses (saya mendapatkan permission deniedkesalahan ketik).

Apakah ada yang tahu tentang penyelesaian masalah ini?

rz.
sumber
3
Apa isi iFrame - apakah src-nya disetel ke domain lain?
James
jika itu adalah domain lain, masih ada cara untuk mengakses konten atau mendaftar acara
adardesign
34
Tidak, karena itu adalah skrip lintas situs, yang dilarang karena alasan keamanan. Solusi saya adalah menggunakan proxy: beri makan HTML dalam kata-kata IFRAME melalui situs saya sendiri sehingga tidak lagi lintas situs dari perspektif browser.
reinierpost
Ini lebih lintas-browser untuk digunakan .contentWindow.documentdaripada .documentpada iframeelemen. Saya akan menyarankan perubahan di atas.
Alan H.
1
satu cara adalah ekstensi chrome
Muhammad Umer

Jawaban:

384

Saya pikir apa yang Anda lakukan tunduk pada kebijakan asal yang sama . Ini harus menjadi alasan mengapa Anda mendapatkan izin kesalahan jenis ditolak .

Onur Bebin
sumber
6
@Pacerier Taruhan terbaik adalah untuk memproksi konten iframe di situs Anda, jika Anda dapat ...
Tracker1
10
@ Tracker1: Dapatkah Anda menyarankan kerangka / api / pola desain apa pun untuk mengimplementasikan solusi proxy ini. Adakah tautan ke contoh atau tutorial, dll? Saya telah mencoba mencari tetapi tidak dapat menemukannya.
Umer Hayat
3
Dalam hal ini, ia berarti menggunakan server http yang melayani halaman domain Anda sebagai proxy - meminta konten dari situs pihak ke-3 dan meneruskannya di dalam tanggapan http kepada klien. Seperti yang mungkin Anda tebak, ini berdampak cepat terhadap respons situs Anda karena permintaan paralel sebelumnya malah dieksekusi secara seri dengan server Anda sebagai hambatan potensial.
rutherford
1
@Pacerier Berpotensi salah satu metode dalam jawaban yang diterima di sini: stackoverflow.com/questions/3076414/… atau lainnya (seperti menggunakan domain Anda sendiri sebagai proxy), tergantung pada apa yang ingin Anda capai.
Mark Amery
4
Sebagai catatan, saya hanya mengatur sesuatu yang serupa: jika Anda tidak ingin hasilnya sangat lambat, cukup atur server web Anda untuk secara langsung mengalihkan kembali permintaan aset (CSS / JS / gambar) ke situs web asli, jadi proxy Anda hanya mengelola permintaan HTML. Saya sedang menjelajahi situs yang jauh di bawah localhost sekarang dan benar-benar transparan :)
neemzy
985

Jika <iframe>dari domain yang sama, elemen-elemennya mudah diakses

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

Referensi

Yasir Laghari
sumber
157
Mengetahui tentang kebijakan asal yang sama itu bagus, tetapi ini adalah jawaban yang melakukan apa yang diinginkan OP. Mengapa jawaban yang lain dipilih sebagai yang benar?
Jason Swett
2
Anda harus menggunakan proxy untuk mendapatkan HTML asal Anda. Misalnya, johnchapman.name/…
mhenry1384
7
@JasonSwett, tebakan saya adalah bahwa masalah OP memang same origin policy, dalam hal ini jawaban ini bukan solusi untuknya.
ANeves
3
@fizzbuzz Kemudian Anda mendapatkan IFrame dengan cara yang sama Anda akan mendapatkan konten id-less lainnya dengan jQuery: Anda memilih tag <IFrame> yang sesuai dengan CSS, menggunakan nama kelas dan nilai atribut untuk mempersempitnya jika perlu.
Auspex
2
Tidak ada metode yang disebut konten untuk iframe.
Renan
88

Anda bisa menggunakan .contents()metode jQuery.

The .contents()Metode ini juga dapat digunakan untuk mendapatkan dokumen isi iframe, jika iframe adalah pada domain yang sama seperti halaman utama.

$(document).ready(function(){
    $('#frameID').load(function(){
        $('#frameID').contents().find('body').html('Hey, i`ve changed content of <body>! Yay!!!');
    });
});
davryusha
sumber
2
saya perlu mendapatkan konten bingkai saya untuk tidak mengatur tubuh ..... Ketika saya melakukan di atas itu tidak berfungsi selalu kembali kosong Tubuh
George Hanna
3
@ DarkoZ Um, sebenarnya jawaban ini datang lebih dulu, jadi jika ada, jawaban lain adalah salinannya
michaelpri
@DarkoZ: meninggalkan komentar asli tidak membuat saya malu, tapi saya buang waktu 30 detik untuk mencoba memahami non-masalah :) Jadi menghapus seluruh diskusi tentang jawaban menjiplak ini mungkin yang terbaik.
Dan Dascalescu
komentar dihapus untuk mencegah kebingungan. permintaan maaf.
Darko Z
43

Jika iframe src berasal dari domain lain Anda masih bisa melakukannya. Anda perlu membaca halaman eksternal ke dalam PHP dan mengulanginya dari domain Anda. Seperti ini:

iframe_page.php

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

    $domain = file_get_contents($URL);

    echo $domain;
?>

Maka sesuatu seperti ini:

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>

Di atas adalah contoh bagaimana mengedit halaman eksternal melalui iframe tanpa akses ditolak dll ...

tukang kayu
sumber
12
Tentu saja, karena server Anda mendapatkan halaman jarak jauh bukan browser pengguna, tidak ada cookie yang akan dikirim ke halaman jarak jauh. YMMV.
Mark Fowler
1
@ Mark: Anda dapat dengan mudah mengirim cookie, data yang diposting, header HTTP, dan yang lainnya jika Anda menerapkannya dengan ekstensi curl. php.net/manual/en/book.curl.php
geon
2
@geon: tetapi browser tidak akan mengirim cookie untuk domain asing ke skrip PHP Anda
ysth
6
@basysmith Berhati-hatilah: ada alasan mengapa same origin policyada, dan proposal jawaban ini tidak kebal terhadapnya.
ANeves
1
Apakah ilegal melakukan hal ini?
Tallboy
32

Saya menemukan cara ini lebih bersih:

var $iframe = $("#iframeID").contents();
$iframe.find('selector');
zupa
sumber
Menyelamatkan pantat saya - saya menjadi gila, menggunakan "$ (" # iframe "). Content (). Find ()" tidak berfungsi karena suatu alasan ... hal yang sama pada dua baris juga. Entah kenapa, tapi itu berhasil.
neminem
30

Menggunakan

iframe.contentWindow.document

dari pada

iframe.contentDocument
pengguna
sumber
Jawaban yang bagus Ini berfungsi untuk iFrames di domain lain. Saya mencoba ini di konsol di Safari dan Firefox.
Aneil Mallavarapu
12
Saya percaya ini hanya akan berfungsi untuk domain lain jika Anda melakukannya dari konsol. Dari skrip, akses tidak akan diizinkan.
yincrash
Ini harus menjadi jawaban yang diterima. Menyelamatkan hidup saya dan bekerja ketika iframe berasal dari domain yang berbeda; meskipun seperti yang disebutkan, hanya di konsol.
Silkfire
bagi saya iframe.contentWindow.document tidak selalu berfungsi. dan ketika tidak saya temukan $ (elem) .contents (). dapatkan (0) tidak
elewinso
Anda dapat memilih "root document" di konsol browser. Ketika Anda memilih "atas" itu tidak akan berfungsi, sebagai akses lintas asal. Jika Anda memilih untuk mengakses atas nama dokumen iframe, tentu saja itu akan memberi Anda akses. Hanya karena Anda bukan peramban, tetapi pemilik peramban.
Sergei Kovalenko
26

Anda perlu melampirkan sebuah acara ke handler onload iframe, dan jalankan js di sana, sehingga Anda memastikan iframe telah selesai memuat sebelum mengaksesnya.

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

Hal di atas akan menyelesaikan masalah 'belum-dimuat', tetapi sehubungan dengan izin, jika Anda memuat halaman di iframe yang berasal dari domain yang berbeda, Anda tidak akan dapat mengaksesnya karena pembatasan keamanan.

Andreas Grech
sumber
ini adalah ide yang bagus, sebenarnya saya mencobanya sama seperti Anda menjawab. Namun, itu tidak bekerja di sekitar izin yang ditolak (itu tidak mengatasi saya harus menunggu sebelum mulai mengakses hal-hal iframe)
rz.
sebenarnya ... tidak apa-apa, tampaknya menunggu masih diperlukan bahkan ketika melakukan ini.
rz.
Fungsi siap berfungsi. Namun, tampaknya itu tidak menunggu konten iframe untuk menyelesaikan pemuatan - hanya untuk dokumen induk bahkan ketika dipanggil pada isi iframe itu sendiri. Saya membayangkan itu juga karena kebijakan asal yang sama.
rz.
3
Beberapa catatan pada kode ini: Anda harus menggunakan iframe.contentDocument daripada .document, dan Anda harus menggunakan .load () alih-alih .ready () untuk menghindari penantian. (Tidak sempurna, tetapi lebih baik)
Rodrigo Queiro
21

Anda dapat menggunakan window.postMessage untuk memanggil fungsi antara halaman dan iframe-nya (lintas domain atau tidak).

Dokumentasi

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>
B. Asselin
sumber
4

Saya lebih suka menggunakan varian lain untuk mengakses. Dari induk, Anda dapat memiliki akses ke variabel dalam iframe anak. $adalah variabel juga dan Anda dapat menerima akses ke panggilan yang adil window.iframe_id.$

Misalnya, window.view.$('div').hide()- sembunyikan semua div di iframe dengan id 'view'

Tapi, itu tidak berhasil di FF. Untuk kompatibilitas yang lebih baik, Anda harus menggunakan

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

Evgeny Karpov
sumber
2

Sudahkah Anda mencoba yang klasik, menunggu pemuatan selesai menggunakan fungsi siap pakai jQuery?

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

K

Khb
sumber
2
Iya. Fungsi siap mulai dijalankan ketika bingkai utama dimuat - bukan ketika iframe dimuat. Menunggu tampaknya menjadi bagian kecil dari masalah. Saya pikir itu ada hubungannya dengan keamanan lintas domain.
rz.
2

Saya membuat kode sampel. Sekarang Anda dapat dengan mudah memahami dari berbagai domain Anda tidak dapat mengakses konten iframe .. Domain yang sama kita dapat mengakses konten iframe

Saya membagikan kode saya kepada Anda, Silakan jalankan kode ini untuk memeriksa konsol. Saya mencetak src gambar di konsol. Ada empat iframe, dua iframe yang berasal dari domain yang sama & dua lainnya dari domain lain (pihak ketiga). Anda dapat melihat dua gambar src ( https://www.google.com/logos/doodles/2015/googles-new-logo -5078286822539264.3-hp2x.gif

dan

https://www.google.com/logos/doodles/2015/arbor-day-2015-brazil-5154560611975168-hp2x.gif ) di konsol dan juga dapat melihat dua kesalahan izin (2 Kesalahan: Izin ditolak untuk mengakses dokumen properti ' '

... irstChild)}, isi: function (a) {return m.nodeName (a, "iframe")? a.contentDocument ...

) yang berasal dari iframe pihak ketiga.

<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>
Zisu
sumber
1

Saya akhirnya di sini mencari konten iframe tanpa jquery, jadi bagi orang lain yang mencari itu, hanya ini:

document.querySelector('iframe[name=iframename]').contentDocument
Jeff Davis
sumber
1

Solusi ini bekerja sama dengan iFrame. Saya telah membuat skrip PHP yang bisa mendapatkan semua konten dari situs web lain, dan yang paling penting adalah Anda dapat dengan mudah menerapkan jQuery khusus Anda ke konten eksternal itu. Silakan merujuk ke skrip berikut yang bisa mendapatkan semua konten dari situs web lain dan kemudian Anda dapat menerapkan cusom jQuery / JS Anda juga. Konten ini dapat digunakan di mana saja, di dalam elemen apa pun atau halaman apa pun.

<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;
}
Ahsan Horani
sumber
0

Untuk kekuatan lebih:

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;
}

dan

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

if (frame_win) {
  $(frame_win.contentDocument || frame_win.document).find('some selector').doStuff();
  ...
}
...
Dominique Fortin
sumber