Как определить, загружается ли веб-страница внутри iframe или непосредственно в окне браузера?

420

Я пишу фрейм-приложение на основе iframe. Теперь я хочу использовать одну и ту же страницу html для рендеринга обычного веб-сайта, а также страницы холста в facebook. Я хочу знать, могу ли я определить, была ли загружена страница внутри iframe или непосредственно в браузере?

Теги:
iframe
facebook

13 ответов

747
Лучший ответ

Браузеры могут блокировать доступ к window.top из-за той же политики происхождения. Ошибки IE также имеют место. Здесь рабочий код:

function inIframe () {
    try {
        return window.self !== window.top;
    } catch (e) {
        return true;
    }
}

top и self являются объектами window (вместе с parent), поэтому вы видите, что ваше окно является верхним окном.

  • 3
    Это похоже на работу в Firefox. Это работает и в других браузерах?
  • 5
    Имея страницу с iframe внутри iframe, чтобы проверить, если мой дочерний iframe был встроен в страницу iframe моего ребенка, я использовал if (parent === top)
Показать ещё 20 комментариев
51

window.frameElement Возвращает элемент (например, <iframe> или <object> ), в который встроено окно, или значение null, если окно находится на верхнем уровне. Таким образом, идентификационный код выглядит как

if (window.frameElement) {
  // in frame
}
else {
  // not in frame
}

Это стандартный и довольно новый метод. Он точно работает в Chrome и Firefox. Я не могу рекомендовать его как универсальное решение, но его следует упомянуть здесь, я думаю.

  • 1
    Обратите внимание, что попытка чтения frameElement вызовет исключение SecurityError в кросс- frameElement , в соответствии с W3C ( WHATWG говорит, что вместо этого должен возвращаться ноль). Так что вы можете захотеть заключить его в оператор try...catch .
  • 3
    null внутри и снаружи iframe
Показать ещё 3 комментария
25

RoBorg правильно, но я хотел добавить примечание.

В IE7/IE8, когда Microsoft добавила вкладки в свой браузер, они сломали одну вещь, которая приведет к хаосу с вашим JS, если вы не будете осторожны.

Представьте себе этот макет страницы:

MainPage.html
  IframedPage1.html   (named "foo")
  IframedPage2.html   (named "bar")
    IframedPage3.html (named "baz")

Теперь в рамке "baz" вы нажимаете ссылку (нет цели, загружается в рамке "baz" ), она отлично работает.

Если загружаемая страница позволяет вызвать ее special.html, она использует JS для проверки того, имеет ли родительский фрейм с именем "bar", он вернет true (ожидается).

Теперь скажем, что на странице special.html при загрузке проверяется родительский фрейм (для существования и его имени, а если это "бар", он перезагружается в рамке рамки, например.

if(window.parent && window.parent.name == 'bar'){
  window.parent.location = self.location;
}

Пока все хорошо. Теперь появляется ошибка.

Предположим, вместо того, чтобы нажимать на исходную ссылку, как обычно, и загружать страницу special.html в рамке "baz" , вы щелкнули ее по середине или решили открыть ее в новой вкладке.

Когда эта новая вкладка загружается ( без родительских кадров вообще! ) IE войдет в бесконечный цикл загрузки страницы!, потому что IE "копирует" структуру кадра в JavaScript, так что новая вкладка имеет родительский элемент, а у этого родителя имя "бар".

Хорошей новостью является проверка:

if(self == top){
  //this returns true!
}

в этой новой вкладке вернет true, и вы можете проверить это нечетное условие.

  • 0
    Исправлена ли ошибка за это время? Я не могу воспроизвести его в IE8. Я всегда получаю правильное window.parent .
  • 1
    Не уверен - я снова запущу свой тестовый набор для IE9 и ниже и выложу обновление.
Показать ещё 1 комментарий
12

Принятый ответ не работал у меня внутри содержимого script расширения Firefox 6.0 (Addon-SDK 1.0): Firefox выполняет содержимое script в каждом: окно верхнего уровня и во всех iframe.

Внутри содержимого script получаю следующие результаты:

 (window !== window.top) : false 
 (window.self !== window.top) : true

Странная вещь в этом выходе заключается в том, что она всегда одинакова независимо от того, выполняется ли код внутри iframe или окна верхнего уровня.

С другой стороны, Google Chrome, кажется, выполняет мой контент script только один раз в окне верхнего уровня, поэтому выше не будет работать.

Что в конечном итоге работало для меня в контенте script в обоих браузерах:

 console.log(window.frames.length + ':' + parent.frames.length);

Без iframe это печатает 0:0, в окне верхнего уровня, содержащем один кадр, он печатает 1:1, а в единственном iframe документа он печатает 0:1.

Это позволяет моему расширению определять в обоих браузерах, если есть какие-либо iframes, а также в Firefox, если он запускается внутри одного из фреймов.

  • 0
    Попробуйте document.defaultView.self === document.defaultView.top или window !== window.top . В сценарии содержимого дополнительного SDK Firefox глобальный объект self - это объект, используемый для связи с основным сценарием.
5

Я использую это:

var isIframe = (self.frameElement && (self.frameElement+"").indexOf("HTMLIFrameElement") > -1);
  • 0
    Почему вы делаете это: .indexOf("HTMLIFrameElement") ?
  • 0
    .indexOf ('foobarbaz')> -1 - это способ проверки «совпадения подстроки» (т. е. можно ли найти «foobarbaz» где-нибудь в строке?), но без использования регулярных выражений. Логически эквивалентно .match (/ foobarbaz /). Он (используется для :-) работы в более широком диапазоне браузеров, и все еще может использоваться либо по привычке, либо из-за опасений по поводу производительности механизма регулярных выражений.
1

Я не уверен, как этот пример работает для старых веб-браузеров, но я использую это для IE, Firefox и Chrome без проблем:

var iFrameDetection = (window === window.parent) ? false : true;
  • 5
    Или просто !(window===window.parent)
  • 3
    окно! == window.parent
1
if(typeof(parent) == 'undefined') {
   console.log('Not Iframe');
}
else {
   console.log('iframe');
}
  • 0
    Это не работа в опере мини 11
  • 0
    в chrome в контексте главного окна window.parent === window имеет значение true. Так что ваш ответ неверен. И это сравнение может быть использовано для проверки (по крайней мере, в Chrome, не проверял его в других браузерах).
Показать ещё 1 комментарий
1

Используйте эту функцию javascript как пример того, как это сделать.

function isNoIframeOrIframeInMyHost() {
// Validation: it must be loaded as the top page, or if it is loaded in an iframe 
// then it must be embedded in my own domain.
// Info: IF top.location.href is not accessible THEN it is embedded in an iframe 
// and the domains are different.
var myresult = true;
try {
    var tophref = top.location.href;
    var tophostname = top.location.hostname.toString();
    var myhref = location.href;
    if (tophref === myhref) {
        myresult = true;
    } else if (tophostname !== "www.yourdomain.com") {
        myresult = false;
    }
} catch (error) { 
  // error is a permission error that top.location.href is not accessible 
  // (which means parent domain <> iframe domain)!
    myresult = false;
}
return myresult;
}
1

Поскольку вы спрашиваете в контексте приложения facebook, вы можете захотеть обнаружить это на сервере при первоначальном запросе. Facebook будет передавать кучу данных запроса, включая ключ fb_sig_user, если он вызывается из iframe.

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

0

Если вы хотите узнать, обращается ли пользователь к вашему приложению со страницы вкладки facebook или проверки холста для подписанного запроса. Если вы этого не сделаете, возможно, пользователь не обращается к Facebook. Чтобы убедиться, что структура полей и полей полей signed_request подтверждена.

С помощью php-sdk вы можете получить подписанный запрос следующим образом:

$signed_request = $facebook->getSignedRequest();

Подробнее о подписанном запросе вы можете узнать здесь:

https://developers.facebook.com/docs/reference/php/facebook-getSignedRequest/

и здесь:

https://developers.facebook.com/docs/reference/login/signed-request/

-1

Это древний фрагмент кода, который я использовал несколько раз:

if (parent.location.href == self.location.href) {
    window.location.href = 'https://www.facebook.com/pagename?v=app_1357902468';
}
  • 6
    Из-за чтения XSS родительское местоположение не допускается.
  • 0
    Чтобы добавить в Энеко Алонсо: это работает (parent.location == self.location)
Показать ещё 1 комментарий
-2
if (window.frames.length != parent.frames.length) { page loaded in iframe }

Но только если число ваших iframe отличается на вашей странице и странице, которые загружают вас в iframe. Не делайте iframe на своей странице, чтобы получить 100% гарантию результата этого кода.

  • 0
    Не очень элегантное решение для определения того, находится ли окно внутри iframe или нет, и нет никаких гарантий, что вы также сможете читать из parent.frames.
-4

Напишите этот javascript на каждой странице

if (self == top)
  { window.location = "Home.aspx"; }

Затем он автоматически перенаправляется на домашнюю страницу.

  • 4
    Ваше перенаправление будет работать, когда вы не, если кадр. Поэтому я не смогу перемещаться по вашему сайту. Во-вторых, существуют методы предотвращения перенаправления с родительской страницы.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню