Подтвердить что ты не робот

Javascript обнаруживает закрытие всплывающего окна, загруженного другим доменом

Я открываю всплывающее окно и привязываю к нему событие onbeforeunload следующим образом:

win = window.open("http://www.google.com", "", "width=300px,height=300px");
win.onbeforeunload = function() {
    //do your stuff here
    alert("Closed");
};

Если я оставил URL пустым, новое всплывающее окно открывается как "about: blank" в качестве адреса, но когда я его закрою, я вижу предупреждение.

Если я открою его, как вы его видите (с внешним URL-адресом), после его закрытия я больше не вижу предупреждения. Любая идея, почему это происходит?

4b9b3361

Ответ 1

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

Здесь код JS:

var openDialog = function(uri, name, options, closeCallback) {
    var win = window.open(uri, name, options);
    var interval = window.setInterval(function() {
        try {
            if (win == null || win.closed) {
                window.clearInterval(interval);
                closeCallback(win);
            }
        }
        catch (e) {
        }
    }, 1000);
    return win;
};

Что он делает: он создает новое окно с предоставленными параметрами, а затем устанавливает функцию checker с интервалом 1 с. Затем функция проверяет, присутствует ли объект окна и имеет ли его закрытое свойство значение false. Если это не так, это означает, что окно (возможно) закрыто и мы должны запустить обратный вызов функции "closeCallback".

Эта функция должна работать со всеми современными браузерами. Некоторое время назад Opera вызывала ошибки при проверке свойств из окон на других доменах - таким образом, блок try..catch. Но я тестировал его сейчас, и кажется, что он работает нормально.

Мы использовали этот метод для создания всплывающих окон "facebook-style" для сайтов, которые не поддерживают их через SDK (ehem... Twitter... ehem). Это потребовало немного дополнительной работы - мы не могли получить никаких сообщений от самого Twitter, но Oauth перенаправила нас обратно в наш домен, а затем мы смогли поместить некоторые данные в объект всплывающего окна, которые были доступны из открывателя. Затем в закрытой функции обратного вызова мы проанализировали эти данные и представили фактические результаты.

Один из недостатков этого метода заключается в том, что обратный вызов вызывается ПОСЛЕ закрытия окна. Ну, это лучшее, что я смог достичь с помощью политики перекрестных доменов.

Ответ 2

Вы можете прослушивать событие "focus" в открывающемся окне, которое запускается, когда пользователь закрывает всплывающее окно.

Ответ 3

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

Вы можете попробовать создать страницу на своем сайте, которая загружает внешний веб-сайт в iframe. Затем вы можете открыть эту страницу и прислушаться к ее разгрузке.

Ответ 4

Я объединил @ от этого, чтобы установить предел интервала (не хотел используйте setTimeout).

Пример (в Typescript объявлен анонимно, чтобы не потерять ссылку на "this"):

  private _callMethodWithInterval = (url: string, callback: function, delay: number, repetitions: number) => {      
    const newWindow = window.open(url, "WIndowName", null, true);

    let x = 0;
    let intervalID = window.setInterval(() => {
      //stops interval if newWindow closed or doesn't exist
      try {
        if (newWindow == null || newWindow.closed) {
          console.info("window closed - interval cleared")
          callback();
          window.clearInterval(intervalID);
        }
      }
      catch (e) {
        console.error(`newWindow never closed or null - ${e}`)
      }
      //stops interval after number of intervals
      if (++x === repetitions) {
        console.info("max intervals reached - interval cleared")        
        window.clearInterval(intervalID);
      }
    }, delay)
  }//end _callMethodWithInterval