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.