Как сделать невидимый iframe

Добавил пользователь Skiper
Обновлено: 04.10.2024

Создание фреймов

Структура HTML-документа с фреймами внешне очень напоминает формат обычного HTML-документа. Как и в обычном HTML-документе, весь код помещен между парными тегами и , а в контейнере располагаются заголовки. Основное отличие документа с фреймами от обычного HTML-документа — у документа с фреймами вместо тега применяется парный тег (от англ. frame set – набор фреймов).
В следующем примере приведена структура HTML-документа с фреймами:

Пример: Структура HTML-документа с фреймами

  • rows — описывает разбиение страницы на строки:
  • cols — описывает разбиение страницы на столбцы:

В значении атрибутов rows и cols необходимо указывать не количество строк или столбцов, а значение ширины и высоты фреймов. Все значения в списке разделяются запятыми. Размеры могут быть указаны в абсолютных единицах (в пикселах) или в процентах:

  • cols="20%, 80%" — окно браузера разбивается на две колонки с помощью атрибута cols, левая колонка занимает 20%, а правая 80% окна браузера.
  • rows="100, *" окно браузера разбивается на два горизонтальных окна с помощью атрибута rows, верхнее окно занимает 100 пикселов, а нижнее — оставшееся пространство, заданное символом звездочки.

Как видно из данного примера, контейнер с атрибутом rows вначале создает два горизонтальных фрейма, а вместо второго фрейма подставляется еще один , который разбивает нижний горизонтальный фрейм на две колонки с помощью атрибута cols, левая колонка занимает занимает 20%, а правая 80% окна браузера.
Если браузер не поддерживает фреймы, то в окне будет отображен текст, расположенный между тегами и . Все, что находится между тегами и , игнорируется браузерами, поддерживающими фреймы. Таким образом разработчику нужно написать код, дублирующий содержимое фреймов другими средствами, и поместить этот код в контейнер , тогда все пользователи смогут увидеть его веб-страницу.
Как уже отмечалось, для вставки в документ отдельного фрейма служит непарный тег . Атрибут src задает документ, который должен отображаться внутри данного фрейма, например: . Если атрибут src отсутствует, отображается пустой фрейм.

Границы или пространство между фреймами

У меня есть страница (A), включая BUTTON с функцией close_window(), однако, когда я вставляю A на свою главную страницу (B), используя iframe, close_window() не может работать так, как ожидалось, поскольку больше нет окно, и я не могу удалить кнопку из iframe, так как A находится в другом домене (проблемы безопасности предотвращают).

Я хочу сделать эту кнопку ярлыком невидимым. И единственный способ, по-моему, положить белое изображение только туда, где эта кнопка существует на моем iframe, извне. Возможно ли это так? Я хочу, чтобы изображение было на вершине iframe?

  • Open with Desktop
  • View raw
  • Copy raw contents Copy raw contents

Copy raw contents

Copy raw contents

IFRAME для AJAX и COMET

Эта глава посвящена IFRAME -- самому древнему и кросс-браузерному способу AJAX-запросов.

Сейчас он используется, разве что, для поддержки кросс-доменных запросов в IE7- и, что чуть более актуально, для реализации COMET в IE9-.

Для общения с сервером создается невидимый IFRAME . В него отправляются данные, и в него же сервер пишет ответ.

Сначала -- немного вспомогательных функций и особенности работы с IFRAME .

Двуличность IFRAME: окно+документ

Что такое IFRAME? На этот вопрос у браузера два ответа

IFRAME -- это HTML-тег: со стандартным набором свойств.

  • Тег можно создавать в JavaScript
  • У тега есть стили, можно менять.
  • К тегу можно обратиться через document.getElementById и другие методы.

IFRAME -- это окно браузера, вложенное в основное

  • IFRAME -- такое же по функционалу окно браузера, как и основное, с адресом и т.п.
    • Если документ в IFRAME и внешнее окно находятся на разных доменах, то прямой вызов методов друг друга невозможен.

    Для достижения цели мы будем работать как с тегом, так и с окном. Они, конечно же, взаимосвязаны.

    В теге свойство contentWindow хранит ссылку на окно.

    Окна также содержатся в коллекции window.frames .

    Больше информации об ифреймах вы можете получить в главе info:iframes.

    IFRAME и история посещений

    IFRAME -- полноценное окно, поэтому навигация в нём попадает в историю посещений.

    Наши запросы в ифрейм -- служебные и для истории не предназначены. К счастью, есть ряд техник, которые позволяют обойти проблему.

    Ифрейм нужно создавать динамически, через JavaScript.

    Когда ифрейм уже создан, то единственный способ поменять его src без попадания запроса в историю посещений:

    Вы можете возразить: "но ведь iframeDoc не всегда доступен! iframe может быть с другого домена -- как быть тогда?". Ответ: вместо смены src этого ифрейма -- создать новый, с новым src .

    POST-запросы в iframe всегда попадают в историю посещений.

    . Но если iframe удалить, то лишняя история тоже исчезнет :). Сделать это можно по окончании запроса.

    Таким образом, общий принцип использования IFRAME : динамически создать, сделать запрос, удалить.

    Бывает так, что удалить по каким-то причинам нельзя, тогда возможны проблемы с историей, описанные выше.

    Приведенная ниже функция createIframe(name, src, debug) кросс-браузерно создаёт ифрейм с данным именем и src .

    name : Имя и id ифрейма

    src : Исходный адрес ифрейма. Необязательный параметр.

    debug : Если параметр задан, то ифрейм после создания не прячется.

    '; var iframe = tmpElem.firstChild; if (!debug) < iframe.style.display = 'none'; >document.body.appendChild(iframe); return iframe; >">

    Кстати, при вставке, если не указан src , тут же произойдёт событие iframe.onload . Пока обработчиков нет, поэтому оно будет проигнорировано.

    Функция postToIframe(url, data, target) отправляет POST-запрос в ифрейм с именем target , на адрес url с данными data .

    url : URL, на который отправлять запрос.

    data : Объект содержит пары ключ:значение для полей формы. Значение будет приведено к строке.

    target : Имя ифрейма, в который отправлять данные.

    Эта функция формирует форму динамически, но, конечно, это лишь один из возможных сценариев использования.

    В IFRAME можно отправлять и существующую форму, включающую файловые и другие поля.

    Запросы GET и POST

    Общий алгоритм обращения к серверу через ифрейм:

    Создаём iframe со случайным именем iframeName .

    Создаём в основном окне объект CallbackRegistry , в котором в CallbackRegistry[iframeName] сохраняем функцию, которая будет обрабатывать результат.

    Отправляем GET или POST-запрос в него.

    Сервер отвечает как-то так:

    . То есть, вызывает из основного окна функцию обработки ( window.name в ифрейме -- его имя).

    Дополнительно нужен обработчик iframe.onload -- он сработает и проверит, выполнилась ли функция CallbackRegistry[window.name] . Если нет, значит какая-то ошибка. Сервер при нормальном потоке выполнения всегда отвечает её вызовом.

    Подробнее можно понять процесс, взглянув на код.

    Мы будем использовать в нём две функции -- одну для GET, другую -- для POST:

    • iframeGet(url, onSuccess, onError) -- для GET-запросов на url . При успешном запросе вызывается onSuccess(result) , при неуспешном: onError() .
    • iframePost(url, data, onSuccess, onError) -- для POST-запросов на url . Значением data должен быть объект ключ:значение для пересылаемых данных, он конвертируется в поля формы.

    Пример в действии, возвращающий дату сервера при GET и разницу между датами клиента и сервера при POST:

    Прямой вызов функции внешнего окна из ифрейма отлично работает, потому что они с одного домена. Если с разных, то нужны дополнительные действия, например:

    В IE8+ есть интерфейс postMessage для общения между окнами с разных доменов.

    В любых, даже самых старых IE, можно обмениваться данными через window.name . Эта переменная хранит "имя" окна или фрейма, которое не меняется при перезагрузке страницы.

    Поэтому если мы сделали POST в на другой домен и он поставил window.name = "Вася" , а затем сделал редирект на основной домен, то эти данные станут доступны внешней странице.

    IFRAME для COMET

    Бесконечный IFRAME -- самый старый способ организации COMET. Когда-то он был основой AJAX-приложений, а сейчас -- используется лишь в случаях, когда браузер не поддерживает современный стандарт WebSocket, то есть для IE9-.

    Этот способ основан на том, что браузер читает страницу последовательно и обрабатывает все новые теги по мере того, как сервер их присылает.

    Таким образом, для передачи данных используется "бесконечный" ифрейм, через который сервер присылает все новые данные.


    Обход проблем с IE

    Такое использование ифреймов является хаком. Поэтому есть ряд проблем:

    1. Показывается индикатор загрузки, "курсор-часики".
    2. При POST в раздаётся звук "клика".
    3. Браузер буферизует начало страницы.

    Мы должны эти проблемы решить, прежде всего, в IE, поскольку в других браузерах есть WebSocket и Server Sent Events .

    Проще всего решить последнюю -- IE не начинает обработку страницы, пока она не загрузится до определенного размера.

    Решение -- забить начало ифрейма чем-нибудь, поставить, например, килобайт пробелов в начале:

    Для решения проблемы с индикацией загрузки и клика мы можем использовать безопасный ActiveX-объект htmlfile . IE не требует разрешений на его создание. Фактически, это независимый HTML-документ.

    Оказывается, если iframe создать в нём, то никакой анимации и звуков не будет.

    1. Основное окно main создаёт вспомогательный объект: new ActiveXObject("htmlfile") . Это HTML-документ со своим window , похоже на встроенный iframe .
    2. В htmlfile записывается iframe .
    3. Цепочка общения: основное окно - htmlfile - ифрейм.

    На самом деле всё еще проще, если посмотреть на код:

    Метод iframeActiveXGet по существу идентичен обычному iframeGet , которое мы рассмотрели. Единственное отличие -- вместо createIframe используется особый метод createActiveXFrame :

    1. Особенности
    2. Проблемы
    3. Двуличность iframe : окно+документ
    4. Отправка запросов на сервер через iframe
      1. GET
      2. POST
      3. Ответ сервера
      1. Решаем сразу все проблемы в IE и получаем идеальный транспорт IE-only.
      2. POST в ActiveX -> iframe

      Этот транспорт - пожалуй, самый универсальный и мощный, но и тонкостей в нем - больше всех

      Для общения с сервером создается невидимый IFrame. Простая смена URL этого iframe - запрос к серверу за данными. Кроме того, в iframe можно отправлять post-запросы
      поставив его имя в атрибут form.target .

      Как правило, iframe - один, и запросы в него по очереди отправляются. Можно сделать и больше ифреймов, чтобы отправлять несколько запросов одновременно.
      Однако, если их больше двух - придется выносить на разные поддомены. Об этом - в секции Обмен данными для документов с разных доменов.

      Особенности

      • Возможна отправка файлов пользователя с диска: POST формы в iframe.

      Проблемы

      • Звук "клика" при переходе запросе в iframe
      • Изменения в history браузера, влияющие на историю посещенных страниц и/или кнопки back-forward. Переходы по служебным URL не должны отражаться на history.
      • Полоса загрузки или курсор-часики при запросе в iframe. Запросы должны быть по возможности прозрачны, невидимы для посетителя.

      А теперь - к реализации и ее особенностям, включая преодоление описанных проблем!

      Двуличность iframe : окно+документ

      Что такое iframe? На этот вопрос у браузера два ответа

      1. HTML-тэг: со стандартным набором свойств
        • Тэг можно создавать в javascript
        • У тега есть стили, можно менять style.height , style.width и т.п.
        • К тегу можно обратиться через document.getElementsByName(name)[0] или document.getElementById(id)
      2. Окно браузера, window
        • Такое же по функционалу окно браузера, как и основное, с адресом и т.п.
        • Основное окно и ифрейм могут общаться через javascript, если находятся на одном домене, или на разных поддоменах одного домена 2 уровня (same origin policy).
        • Можно получить через window.frames['имя фрейма']

      Когда мы говорим о переводе iframe на новый URL - подразумеваем "окно". Когда собираемся создавать его и запихивать в DOM - конечно, "тег".

      В теге iframe хранится ссылка на окно. В зависимости от браузера, это либо iframe.contentDocument , либо iframe.contentWindow.document , либо iframe.document .

      Из страницы внутри окна iframe можно пройти к родительскому окну через window.parent, и, если разрешает same origin policy, даже вызвать функцию/получить тег iframe .

      Отправка запросов на сервер через iframe

      GET-запрос - всего лишь перевод iframe на новый URL. Его лучше всего осуществлять вызовом iframeDocument.location.src.replace(newURL) .
      Такой синтаксис в отличие от сабмита GET-формы в iframe или iframeDocument.location.src=. , оставляет history чистой в ряде браузеров. Так что переходы между адресами внутри iframe не отразятся на
      кнопках back-forward и списке посещенных страниц..

      Для поста - достаточно задать форме form атрибут form.target='имя ифрейма' и вызвать form.submit() . Таким способом можно отправлять на сервер файлы, и вообще,
      все что может содержать форма HTML.

      Ответ сервера

      Сервер получает запрос, и генерирует в ответ страницу, которая, как правило, передает результат в основное окно через специальную функцию-каллбэк.
      В примерах такая функция появится чуть позже, при рассмотрении невидимых ифреймов.

      iframe и history


      Для браузера iframe - такое же окно, как и основное. Соответственно, переходы в нем на разные URL должны попадать в историю, браузить туда-сюда можно через back/forward.
      Например, вот:

      Клик на Туда соответствует переходу по адресу there.html, а клик на Сюда - по адресу here.html (он же - начальный адрес).

      Для начала проверим - загрязняется ли history. Для этого в новой вкладке(или окне) откроем урл примера. Затем, нажимая на кнопки - смотрим, не заработала ли
      кнопка back. Если заработала - в history появился новый, лишний элемент. Лишний - потому, что автоматические, служебные переходы по специальным адресам
      попадать в history не должны, они там лишние.

      Кроме того, генерирует ли IE звук клика при переходе по служебному адресу? Как правило, при стандартной звуковой схеме Windows такой звук есть.

      Результаты тестов зависят от браузера, ОС и т.п. Обычно получиться так, что при POST history загрязняется, а при GET - нет.

      Динамически создаем iframe

      Создать ифрейм - так же просто, как и любой другой элемент. Пожалуй, единственная подстава - в IE свойство name должно обязательно задаваться при создании элемента.
      Т.е, нельзя сначала сделать iframe , а потом присвоить ему name (то же самое и для input, и т.п.) - будут проблемы. Поэтому приходится делать отдельную проверку на isIE.

      Приведенная ниже функция создает ифрейм с именем fname, если его еще нет, и при создании задает исходный адрес src . Если ифрейм с таким именем уже есть - он просто возвращается без дополнительных действий.

      Если не задан параметр debug , то ифрейм после создания делается невидимым.

      Динамическое создание ифрейма преследует две цели:

      1. Делаем HTML чище
      2. Динамический ифрейм - еще одна мера против загрязнения history

      Вы можете самостоятельно протестировать влияние динамической генерации на звук клика в IE и кнопки back-forward.

      Решаем сразу все проблемы в IE и получаем идеальный транспорт IE-only.

      Следующий пример работает только в IE. Он создает невидимый iframe, при запросе через который нет ни клика ни лишней хистори, ни индикатора загрузки.

      Если Вы находитесь в IE, то можете заметить, что переходы по этому ифрейму абсолютно незаметны для пользователя. Идеал, да и только . Он создается при помощи
      слабо документированной, но безопасной возможности ActiveX. Никаких специальных опций браузера для нее включать не надо.

      Как видно из примера, для изоляции ифрейма создается промежуточный документ ActiveX. Поэтому операции над ифреймом и не видны из основного окна.Здесь получается, что объектов window не два, как обычно (основное окно + ифрейм), а три:

      1. Основное окно window
      2. Окно документа htmlfile - доступно как IEFrameDocument.parentWindow
      3. Окно ифрейма - доступно как IEFrameNode.contentWindow , или с использованием getIframeDocument

      И здесь есть некоторые сложности. Чтобы вызвать функцию основного окна, javascript-код изнутри ифрейма должен пробиться через промежуточный htmlfile .
      Но htmlfile - это отдельный HTML-документ. Политика безопасности same origin policy запрещает взаимный javascript-доступ между документами
      с сайта и новосозданным htmlfile.

      Чтобы такой доступ получить, нужно заранее, из основного окна, протянуть ссылку из окна htmlfile в основное окно:

      Если ссылка между окнами уже существует, то same origin policy не проверяется, так что документ с сервера может быть, например, таким:

      Обмен данными проиллюстрирован на рисунке:

      POST в ActiveX -> iframe

      Если Вы решите использовать этот подход - позвольте мне сэкономить возможные часы копания в отладчике. До этого обсуждался метод GET.
      В нем достаточно ссылки на iframe .

      С другой стороны, в методе POST нужно присвоить form.target не сам иферейм, а имя ифрейма, причем этот ифрейм должен быть виден из текущего окна.

      Легко проверить, что простой пост в фрейм "frame3" (в примере) не даст результата, т.к этот фрейм не виден.

      Для того, чтобы форма увидела ифрейм, ее нужно создать в том же окне. Это можно сделать массой способов. Например, добавить нужные скрипты в htmlfile:

      Читайте также: