jQuery / JavaScript: iframe'in içeriğine erişme


791

JQuery kullanarak bir iframe içinde HTML manipüle etmek istiyorum.

JQuery işlevinin bağlamını iframe belgesi olacak şekilde ayarlayarak bunu yapabileceğimi düşündüm:

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

Ancak bu işe yaramıyor gibi görünüyor. Denetimin bir frames['nameOfMyIframe']kısmı undefined, iframe'in yüklenmesi için bir süre beklemedikçe , değişkenlerin olduğunu gösteriyor . Ancak, iframe yüklendiğinde değişkenlere erişilemez ( permission denied-type hataları alıyorum ).

Herkes bu konuda bir çözüm biliyor mu?


3
İFrame ne içerir - src başka bir alana ayarlanmış mı?
James

başka bir alan
adındaysa

34
Hayır, çünkü bu güvenlik nedeniyle yasak olan siteler arası komut dosyası oluşturma olacaktır. Benim çözümüm bir proxy kullanmaktı: HTML'yi IFRAME kelimesi kelimesine kendi sitem aracılığıyla beslemek, böylece artık tarayıcı perspektifinde siteler arası değil.
reinierpost

Kullanmak , öğeye .contentWindow.documentgöre daha fazla çapraz tarayıcıdır . Yukarıdaki değişikliği önereceğim. .documentiframe
Alan H.

1
bir yolu krom uzantıları
Muhammad Umer

Yanıtlar:


384

Bence yaptığınız şey aynı köken politikasına tabidir . İzin verilmeyen tür hataları alma nedeniniz bu olmalıdır .


6
@Pacerier Yapabiliyorsanız, sitenizdeki iframe içeriğini proxy
yapmaktır

10
@ Tracker1: Bu proxy çözümünü uygulamak için herhangi bir çerçeve / api / tasarım deseni önerebilir misiniz? Örnek veya öğretici vb. Aramaya çalıştım ama bulamadım.
Umer Hayat

3
Bu durumda, alanınızın sayfasını proxy olarak sunan http sunucusunu kullanmak anlamına gelir - 3. taraf siteden içerik isteyin ve istemciye http yanıtında iletin. Tahmin edebileceğiniz gibi, daha önce paralel istekler yerine potansiyel bir darboğaz olarak sunucunuzla seri olarak yürütüldüğünden, sitenizin yanıt verebilirliğini hızla etkiler.
rutherford

1
@Pacerier Buraya kabul edilen yanıttaki yöntemlerden herhangi biri: elde etmek istediğiniz şeye bağlı olarak stackoverflow.com/questions/3076414/… veya diğerleri (kendi etki alanınızı proxy olarak kullanma gibi).
Mark Amery

4
Kayıt için sadece benzer bir şey ayarladım: sonucun inanılmaz derecede yavaş olmasını istemiyorsanız, web sunucunuzu varlık varlıklarını (CSS / JS / resimler) doğrudan orijinal web sitesine yönlendirecek şekilde ayarlayın, böylece proxy'niz yalnızca HTML isteklerini yönetir. Şu anda localhost altında uzak bir siteye göz atıyorum ve kesinlikle şeffaf :)
neemzy

985

Eğer <iframe>aynı alan adına, elementler gibi kolayca erişilebilir

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

Referans


157
Aynı köken politikasını bilmek harika ama OP'nin istediği yanıtı bu. Diğer cevap neden doğru cevap olarak seçildi?
Jason Swett

2
HTML'yi kaynağınıza almak için bir proxy kullanmanız gerekir. Örneğin, johnchapman.name/…
mhenry1384 17:11

7
@JasonSwett, tahminim OP'nin probleminin gerçekten olduğu same origin policy, bu durumda bu cevap onun için bir çözüm değil.
ANeves

3
@fizzbuzz Daha sonra IFrame'i jQuery ile kimliksiz diğer içeriklerle aynı şekilde elde edersiniz: CSS ile uygun <IFrame> etiketini seçersiniz, gerekirse sınıf adlarını ve özellik değerlerini daraltmak için bu karakterleri daraltın.
Auspex

2
İframe için içerik adı verilen bir yöntem yoktur .
Renan

88

.contents()JQuery yöntemini kullanabilirsiniz .

Bu .contents()yöntem, iframe ana sayfayla aynı etki alanındaysa, iframe'in içerik belgesini almak için de kullanılabilir.

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

2
Ben vücudu ayarlamak için değil i çerçeve içeriği almak gerekir ..... Yukarıdakileri yaptığımda her zaman işe yaramaz Boş Vücut
George Hanna

3
@DarkoZ Um, aslında bu cevap önce geldi, bu yüzden bir şey varsa, diğer cevap
kopyaydı

@DarkoZ: Orijinal yorumu bırakmak beni utandırmadı, ama bir konuyu anlamaya çalışırken 30 saniye gibi israf ettim :) Yani intihal eden bir cevap hakkındaki tüm tartışmayı kaldırmak en iyisi olabilir.
Dan Dascalescu

karışıklığı önlemek için yorumlar kaldırıldı. özürlerimi.
Darko Z

43

İframe src başka bir etki alanından geliyorsa, bunu yine de yapabilirsiniz. Harici sayfayı PHP'ye okumanız ve alan adınızdan tekrarlamanız gerekir. Bunun gibi:

iframe_page.php

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

    $domain = file_get_contents($URL);

    echo $domain;
?>

Sonra böyle bir şey:

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>

Yukarıdaki, dış bir sayfanın erişim reddedilmeden vb. Olmadan bir iframe aracılığıyla nasıl düzenleneceğine bir örnektir.


12
Elbette, sunucunuz kullanıcının tarayıcısını değil uzak sayfayı aldığından uzak sayfaya çerez gönderilmez. YMMV.
Mark Fowler

1
@Mark: Curl uzantısıyla uygularsanız çerezleri, yayınlanan verileri, HTTP başlıklarını ve neleri kolayca gönderebilirsiniz. php.net/manual/en/book.curl.php
Geon

2
@geon: ancak tarayıcı PHP betiğinize yabancı alan adı için çerez göndermez
ysth

6
@basysmith Dikkatli olun: var olmasının bir nedeni same origin policyvardır ve bu yanıtın teklifi ona karşı bağışık değildir.
ANeves

1
bunu yapmak hiçbir şekilde yasadışı mı?
Tallboy

32

Bu yolu daha temiz buluyorum:

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

Popomu kurtardım - "$ (" # iframe "). Content (). Find ()" herhangi bir nedenden dolayı çalışmıyordu ... iki satır üzerinden aynı şeyi yaptım. Neden bilmiyorum, ama işe yarıyor.
neminem

30

kullanım

iframe.contentWindow.document

onun yerine

iframe.contentDocument

Mükemmel cevap. Bu, diğer alanlardaki iFrame'ler için geçerlidir. Bunu Safari ve Firefox'taki konsolda denedim.
Aneil Mallavarapu

12
Yalnızca konsoldan yapıyorsanız diğer alanlar için çalışacağına inanıyorum. Bir komut dosyasından erişime izin verilmez.
yincrash

Bu kabul edilen cevap olmalı. Hayatımı kurtardı ve iframe farklı bir alandan olduğunda çalışıyor; belirtildiği gibi, sadece konsolda.
ipek ateş

benim için iframe.contentWindow.document her zaman çalışmaz. ve bu olmadığında $ (elem) .contents (). get (0) yapar
elewinso

tarayıcı konsolunda "kök belge" yi seçebilirsiniz. "Üst" seçeneğini belirlediğinizde, çapraz menşe erişimi olarak çalışmaz. İframe belgesi adına erişmeyi seçerseniz, elbette size erişim sağlayacaktır. Sadece bir tarayıcı değil, tarayıcı sahibisiniz.
Sergei Kovalenko

26

Bir iframe'in onload işleyicisine bir olay eklemeniz ve orada js'yi çalıştırmanız gerekir; böylece iframe'e erişmeden önce yüklemeyi bitirdiğinizden emin olun.

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

Yukarıdakiler 'henüz yüklenmemiş' sorununu çözecektir, ancak izinlerle ilgili olarak, iframe'de farklı bir alandan bir sayfa yüklüyorsanız, güvenlik kısıtlamaları nedeniyle bu sayfaya erişemezsiniz.


bu iyi bir fikir, aslında cevapladığınız gibi deniyordum. Ancak, reddedilen izin etrafında çalışmaz (iframe öğelerine erişmeye başlamadan önce beklemek zorunda
kalmamı ele alır

aslında ... boşver, bunu yaparken bile beklemenin hala gerekli olduğu anlaşılıyor.
rz.

Hazır işlevi çalışır. Bununla birlikte, iframe içeriğinin yüklemeyi bitirmesini beklemiyor gibi görünüyor - iframe'in içeriğinde çağrıldığında bile yalnızca üst belge için. Bunun aynı köken politikasından da kaynaklandığını düşünüyorum.
rz.

3
Bu kodla ilgili birkaç not: .document yerine iframe.contentDocument ve beklemekten kaçınmak için .ready () yerine .load () kullanmalısınız. (Mükemmel değil, ama daha iyi)
Rodrigo Queiro

21

Window.postMessage öğesini sayfa ile onun iframe'i (etki alanları arası veya değil) arasında bir işlev çağırmak için kullanabilirsiniz.

belgeleme

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

Erişim için başka bir varyant kullanmayı tercih ediyorum. Üst öğeden alt iframe içindeki değişkene erişebilirsiniz. $bir değişkendir ve sadece çağrıya erişebilirsiniz window.iframe_id.$

Örneğin, window.view.$('div').hide()- iframe'deki tüm div'leri 'view' kimliğiyle gizle

Ancak, FF'de çalışmaz. Daha iyi uyumluluk için kullanmalısınız

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


2

JQuery'nin yerleşik hazır işlevini kullanarak yükün tamamlanmasını bekleyerek klasiği denediniz mi?

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

K


2
Evet. Hazır çerçeve, iframe yüklendiğinde değil ana çerçeve yüklendiğinde yürütülmeye başlar. Bekleme, sorunun küçük bir parçası gibi görünüyor. Bunun etki alanları arası güvenlikle ilgili olduğunu düşünüyorum.
rz.

2

Örnek bir kod oluşturuyorum. Artık iframe içeriğine erişemediğiniz farklı alan adlarından kolayca anlayabilirsiniz .. iframe içeriğine erişebildiğimiz aynı alan adı

Size kodumu paylaşıyorum, lütfen bu kodu çalıştırın konsolu kontrol edin. Image src'yi konsoldan yazdırıyorum. Dört iframe, iki iframe aynı alan adından geliyor ve diğer ikisi diğer alan adından (üçüncü taraf) geliyor. İki resim src ( https://www.google.com/logos/doodles/2015/googles-new-logo -5078286822539264,3-hp2x.gif

ve

https://www.google.com/logos/doodles/2015/arbor-day-2015-brazil-5154560611975168-hp2x.gif ) konsolda ve ayrıca iki izin hatası (2 Hata: Mülkiyet belgesine erişim engellendi) '

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

) üçüncü taraf iframe'den geliyor.

<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

Burada jquery olmadan bir iframe içeriği almak için sona erdi, bu yüzden bunu arayan herkes için, sadece bu:

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

1

Bu çözüm iFrame ile aynı şekilde çalışır. Ben diğer web sitesinden tüm içeriği alabilirsiniz bir PHP komut dosyası oluşturduk ve en önemli kısmı kolayca bu harici içeriğe özel jQuery uygulayabilirsiniz. Lütfen diğer web sitesinden tüm içeriği alabilen aşağıdaki komut dosyasına bakın ve daha sonra cusom jQuery / JS'nizi de uygulayabilirsiniz. Bu içerik herhangi bir yerde, herhangi bir öğenin içinde veya herhangi bir sayfada kullanılabilir.

<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

Daha fazla sağlamlık için:

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

ve

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

if (frame_win) {
  $(frame_win.contentDocument || frame_win.document).find('some selector').doStuff();
  ...
}
...
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.