jQuery / JavaScript: доступ до вмісту iframe


791

Я хотів би маніпулювати HTML всередині iframe за допомогою jQuery.

Я думав, що зможу це зробити, встановивши контекст функції jQuery як документ iframe, щось на зразок:

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

Однак це, здається, не працює. Трохи перевірки показує мені, що змінні в frames['nameOfMyIframe'], undefinedякщо я не чекаю деякий час, щоб завантажився кадр iframe. Однак, коли iframe завантажує, змінні недоступні (я отримую permission denied-тип помилок).

Хтось знає про вирішення цього питання?


3
Що містить iFrame - чи його src встановлено на інший домен?
Джеймс

якщо це інший домен, чи все ж є спосіб отримати доступ до його вмісту або зареєструвати подію
adardesign

34
Ні, тому що це буде міжсайтовий сценарій, який заборонений з міркувань безпеки. Моє рішення полягало у використанні проксі: подавати HTML у дослівному форматі IFRAME через мій власний сайт, щоб він більше не переглядав веб-сайт з точки зору браузера.
reinierpost

Використовувати більше крос-браузер, .contentWindow.documentніж .documentна iframeелементі. Я запропоную зміни вище.
Алан Х.

1
один із способів - хромовані розширення
Мухаммед Умер

Відповіді:


384

Я думаю, що те, що ти робиш, підлягає тій самій політиці походження . Це повинно бути причиною, через яку ви отримуєте дозвол, яким відмовлено в помилках типу .


6
@Pacerier Найкраща ставка - це проксі вміст iframe на вашому сайті, якщо ви можете ...
Tracker1

10
@ Tracker1: Чи можете ви запропонувати будь-яку схему frame / api / design для реалізації цього проксі-рішення. Будь-які посилання на приклад, підручник тощо? Я намагався шукати, але не міг знайти жодного.
Умер Хаят

3
У цьому випадку він має на увазі використовувати http-сервер, який обслуговує сторінку вашого домену як проксі - запитуйте вміст із сторонніх веб-сайтів та пересилайте його у відповідь http клієнту. Як ви, напевно, здогадуєтесь, це швидко впливає на чутливість вашого сайту, оскільки раніше паралельні запити виконуються послідовно із вашим сервером як потенційне вузьке місце.
Резерфорд

1
@Pacerier Потенційно будь-який із методів у прийнятій тут відповіді: stackoverflow.com/questions/3076414/… або інші (наприклад, використання власного домену як проксі), залежно від того, що ви хочете досягти.
Марк Амері

4
Для запису я просто налаштував щось подібне: якщо ви не хочете, щоб результат був неймовірно повільним, просто налаштуйте свій веб-сервер для прямої перенаправлення запитів активів (CSS / JS / образи) на початковий веб-сайт, щоб ваш проксі управляє лише запитами HTML. Я переглядаю віддалений сайт під localhost зараз, і це абсолютно прозоро :)
neemzy

985

Якщо <iframe>з одного домену, елементи легко доступні як

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

Довідково


157
Знання про ту саму політику походження є чудовою, але це відповідь, яка робить те, чого хотів ОП. Чому іншу відповідь вибрали правильну?
Jason Swett

2
Ви повинні використовувати проксі, щоб отримати HTML у своєму походження. Наприклад, johnchapman.name/…
mhenry1384

7
@JasonSwett, я гадаю, що проблема ОП - це справді та same origin policy, в цьому випадку ця відповідь не є рішенням для нього.
ANeves

3
@fizzbuzz Тоді ви отримаєте IFrame так само, як і будь-який інший вміст, що не містить id, з jQuery: ви вибираєте відповідний тег <IFrame> з CSS, використовуючи назви класів та значення атрибутів, щоб при необхідності звузити його.
Auspex

2
Не існує методу, який називається вмістом для iframe.
Ренан

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
мені потрібно отримати вміст кадру я не встановлювати тіло ..... Коли я роблю вище, це не працює, завжди повертайте порожнє тіло
Джордж Ханна

3
@DarkoZ Гм, насправді ця відповідь прийшла першою, тому, якщо що, інша відповідь була копія
michaelpri

@DarkoZ: залишення оригінального коментаря не засмутило вас, але я витратив, як 30 секунд, намагаючись зрозуміти непроблему :) Тож найкраще видалити всю цю дискусію про плагіатизуючу відповідь.
Дан Даскалеску

коментарі видалено, щоб запобігти плутанині. вибачення.
Darko Z

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: Ви можете легко надсилати файли cookie, опубліковані дані, заголовки HTTP та інше, якщо реалізувати їх за допомогою розширення curl. php.net/manual/en/book.curl.php
geon

2
@geon: але браузер не відправлятиме куки для зовнішнього домену на ваш PHP скрипт
ysth

6
@basysmith Будьте уважні: є причина, чому same origin policyіснує, і пропозиція цієї відповіді не захищена від цього.
ANeves

1
чи це незаконно будь-яким чином це робити?
Талбой

32

Я вважаю цей спосіб чистішим:

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

Врятував мою недопалку - я божеволію, використовуючи "$ (" # iframe "). Не знаю чому, але це працює.
neminem

30

Використовуйте

iframe.contentWindow.document

замість

iframe.contentDocument

Чудова відповідь. Це працює для iFrames в інших областях. Я спробував це в консолі на Safari та Firefox.
Aneil Mallavarapu

12
Я вважаю, що це працюватиме лише для інших доменів, якщо ви робите це з консолі. Зі скрипту доступ не буде дозволений.
yincrash

Це має бути прийнятою відповіддю. Врятувало моє життя та роботи, якщо рамка з іншого домену; хоча, як було сказано, лише в консолі.
шовковий вогонь

для мене iframe.contentWindow.document не завжди працює. і коли це не так, я виявив, що $ (elem) .contents (). get (0) робить
elewinso

ви можете вибрати "кореневий документ" на консолі браузера. Вибравши "верхній", він не працюватиме як доступ з перехресним походженням. Якщо ви вирішите отримати доступ від імені документа iframe, звичайно, він надасть вам доступ. Просто тому, що ви не веб-переглядач, а власник браузера.
Сергій Коваленко

26

Вам потрібно приєднати подію до обробника завантаження iframe і виконати 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)
rz.

насправді ... неважливо, здається, що чекати все-таки потрібно навіть при цьому.
рз.

Готова функція працює. Однак, схоже, він не чекає, коли вміст iframe закінчиться завантаженням - лише для батьківського документа, навіть коли викликається вміст самого кадру iframe. Я думаю, це також через ту саму політику походження.
рз.

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

Я вважаю за краще використовувати інший варіант для доступу. Від батьків ви можете мати доступ до змінної у дочірньому кадрі. $також є змінною, і ви можете отримати доступ до її простого дзвінка window.iframe_id.$

Наприклад, window.view.$('div').hide()- приховати всі divs в iframe з id 'view'

Але це не працює у FF. Для кращої сумісності вам слід скористатися

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


2

Ви спробували класичну, очікуючи завершення завантаження за допомогою вбудованої функції готової jQuery?

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

К


2
Так. Готова функція починає виконуватись при завантаженні основного кадру, а не при завантаженні iframe. Очікування, здається, є невеликою частиною проблеми. Я думаю, що це стосується міждоменної безпеки.
рз.

2

Я створюю зразок коду. Тепер ви можете легко зрозуміти з іншого домену, що ви не можете отримати доступ до вмісту 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 Помилка: Дозволу відмовлено у доступі до документа власності '

... irstChild)}, content: 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>

1

Я закінчив тут шукати вміст iframe без jquery, тому для всіх, хто шукає цього, це просто так:

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

1

Це рішення працює так само, як iFrame. Я створив PHP-скрипт, який може отримати весь вміст з іншого веб-сайту, і найважливіша частина - ви можете легко застосувати свій власний jQuery до цього зовнішнього контенту. Будь ласка, зверніться до наступного сценарію, який може отримати весь вміст з іншого веб-сайту, і тоді ви також можете застосувати ваш cusom 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();
  ...
}
...
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.