[javascript] Chrome에서 차단 된 팝업 감지

이 질문대한 답변에 설명 된대로 다른 브라우저에서 팝업이 차단되었는지 여부를 감지하는 자바 스크립트 기술을 알고 있습니다. 다음은 기본 테스트입니다.

var newWin = window.open(url);

if(!newWin || newWin.closed || typeof newWin.closed=='undefined')
{
    //POPUP BLOCKED
}

그러나 이것은 Chrome에서 작동하지 않습니다. 팝업이 차단되면 “POPUP BLOCKED”섹션에 도달하지 않습니다.

물론 Chrome이 실제로 팝업을 차단하지 않고 “차단 된”팝업을 나열하는 오른쪽 하단 모서리에 작은 최소화 된 창에서 열기 때문에 테스트는 어느 정도 작동합니다.

내가하고 싶은 것은 팝업이 Chrome의 팝업 차단기에 의해 차단되었는지 알 수 있다는 것입니다. 기능 감지를 위해 브라우저 스니핑을 피하려고합니다. 브라우저 스니핑없이이 작업을 수행 할 수있는 방법이 있습니까?

편집 : 지금 메이커의 사용을 시도 newWin.outerHeight, newWin.left이를 달성하기 위해, 그리고 다른 유사한 속성을. Google 크롬은 팝업이 차단되면 모든 위치 및 높이 값을 0으로 반환합니다.

불행히도 팝업이 실제로 알려지지 않은 시간 동안 열린 경우에도 동일한 값을 반환합니다. 마법 같은 기간 (내 테스트에서 몇 초) 후에 위치 및 크기 정보가 올바른 값으로 반환됩니다. 다시 말해, 나는 이것을 알아내는 데 아직 더 가깝지 않습니다. 어떤 도움을 주시면 감사하겠습니다.



답변

당신이 말하는 “마법의 시간”은 아마도 팝업의 DOM이로드되었을 때일 것입니다. 아니면 모든 것 (이미지, 아웃 보드 CSS 등)이로드되었을 수도 있습니다. 팝업에 매우 큰 그래픽을 추가하여 쉽게 테스트 할 수 있습니다 (먼저 캐시를 지우십시오!). jQuery (또는 이와 유사한 것)와 같은 자바 스크립트 프레임 워크를 사용하는 경우, 창 오프셋을 확인하기 전에 DOM이로드 될 때까지 기다릴 ready () 이벤트 (또는 유사한 것)를 사용할 수 있습니다. 이것의 위험은 Safari 감지가 충돌하는 방식으로 작동한다는 것입니다. 팝업의 DOM은 열려고하는 창에 대해 유효한 핸들을 제공하기 때문에 Safari에서 절대로 ready ()되지 않습니다. 아니. (사실, 위의 팝업 테스트 코드가 사파리에서 작동하지 않을 것이라고 생각합니다.)

당신이 할 수있는 최선의 방법은 테스트를 setTimeout ()에 래핑하고 테스트를 실행하기 전에 로딩을 완료하기 위해 팝업에 3-5 초를주는 것입니다. 완벽하지는 않지만 적어도 95 %는 작동합니다.

다음은 Chrome 부분없이 브라우저 간 감지에 사용하는 코드입니다.

function _hasPopupBlocker(poppedWindow) {
    var result = false;

    try {
        if (typeof poppedWindow == 'undefined') {
            // Safari with popup blocker... leaves the popup window handle undefined
            result = true;
        }
        else if (poppedWindow && poppedWindow.closed) {
            // This happens if the user opens and closes the client window...
            // Confusing because the handle is still available, but it's in a "closed" state.
            // We're not saying that the window is not being blocked, we're just saying
            // that the window has been closed before the test could be run.
            result = false;
        }
        else if (poppedWindow && poppedWindow.test) {
            // This is the actual test. The client window should be fine.
            result = false;
        }
        else {
            // Else we'll assume the window is not OK
            result = true;
        }

    } catch (err) {
        //if (console) {
        //    console.warn("Could not access popup window", err);
        //}
    }

    return result;
}

내가하는 일은 부모로부터이 테스트를 실행하고 setTimeout ()에 래핑하여 자식 창을로드하는 데 3-5 초를주는 것입니다. 자식 창에서 테스트 함수를 추가해야합니다.

기능 검사() {}

팝업 차단기 감지기는 “테스트”기능이 하위 창의 구성원으로 존재하는지 여부를 테스트합니다.

2015 년 6 월 15 일 추가 :

이를 처리하는 현대적인 방법은 window.postMessage ()를 사용하여 자식이 부모에게 창이로드되었음을 알리도록하는 것입니다. 접근 방식은 비슷하지만 (하위가 부모에게로드되었음을 알립니다) 의사 소통 수단이 향상되었습니다. 나는 아이로부터이 교차 도메인을 할 수 있었다.

$(window).load(function() {
  this.opener.postMessage({'loaded': true}, "*");
  this.close();
});

부모는 다음을 사용하여이 메시지를 수신합니다.

$(window).on('message', function(event) {     
  alert(event.originalEvent.data.loaded)
}); 

도움이 되었기를 바랍니다.


답변

InvisibleBacon의 snipet에 대한 한 가지 개선 사항 (IE9, Safari 5, Chrome 9 및 FF 3.6에서 테스트 됨) :

var myPopup = window.open("popupcheck.htm", "", "directories=no,height=150,width=150,menubar=no,resizable=no,scrollbars=no,status=no,titlebar=no,top=0,location=no");
if (!myPopup)
    alert("failed for most browsers");
else {
    myPopup.onload = function() {
        setTimeout(function() {
            if (myPopup.screenX === 0) {
                alert("failed for chrome");
            } else {
                // close the test window if popups are allowed.
                myPopup.close();
            }
        }, 0);
    };
}


답변

다음은 팝업 차단기 검사를 위한 jQuery 솔루션입니다. FF (v11), Safari (v6), Chrome (v23.0.127.95) 및 IE (v7 및 v9)에서 테스트되었습니다. _displayError 함수를 업데이트하여 적절하다고 판단되는 오류 메시지를 처리합니다.

var popupBlockerChecker = {
        check: function(popup_window){
            var _scope = this;
            if (popup_window) {
                if(/chrome/.test(navigator.userAgent.toLowerCase())){
                    setTimeout(function () {
                        _scope._is_popup_blocked(_scope, popup_window);
                     },200);
                }else{
                    popup_window.onload = function () {
                        _scope._is_popup_blocked(_scope, popup_window);
                    };
                }
            }else{
                _scope._displayError();
            }
        },
        _is_popup_blocked: function(scope, popup_window){
            if ((popup_window.innerHeight > 0)==false){ scope._displayError(); }
        },
        _displayError: function(){
            alert("Popup Blocker is enabled! Please add this site to your exception list.");
        }
    };

용법:

var popup = window.open("http://www.google.ca", '_blank');
popupBlockerChecker.check(popup);

도움이 되었기를 바랍니다! 🙂


답변

Rich의 대답은 더 이상 Chrome에서 작동하지 않습니다. Chrome이 실제로 팝업 창에서 Javascript를 실행하는 것 같습니다. 차단 된 팝업을 확인하기 위해 screenX 값 0을 확인했습니다. 또한 확인하기 전에이 속성이 최종적인지 확인하는 방법을 찾았다 고 생각합니다. 이는 도메인의 팝업에서만 작동하지만 다음과 같이 onload 핸들러를 추가 할 수 있습니다.

var myPopup = window.open("site-on-my-domain", "screenX=100");
if (!myPopup)
    alert("failed for most browsers");
else {
    myPopup.onload = function() {
        setTimeout(function() {
            if (myPopup.screenX === 0)
                alert("failed for chrome");
        }, 0);
    };
}

많은 사람들이보고 한 것처럼 “screenX”속성은 가끔 온로드 후에도 실패한 팝업에 대해 0이 아닌 것으로보고합니다. 이 동작도 경험했지만 0ms 시간 초과 후에 확인을 추가하면 screenX 속성이 항상 일관된 값을 출력하는 것처럼 보입니다.

이 스크립트를 더 강력하게 만드는 방법이 있는지 알려주세요. 그래도 내 목적을 위해 일하는 것 같습니다.


답변

이것은 나를 위해 일했습니다.

    cope.PopupTest.params = 'height=1,width=1,left=-100,top=-100,location=no,toolbar=no,menubar=no,scrollbars=no,resizable=no,directories=no,status=no';
    cope.PopupTest.testWindow = window.open("popupTest.htm", "popupTest", cope.PopupTest.params);

    if( !cope.PopupTest.testWindow
        || cope.PopupTest.testWindow.closed
        || (typeof cope.PopupTest.testWindow.closed=='undefined')
        || cope.PopupTest.testWindow.outerHeight == 0
        || cope.PopupTest.testWindow.outerWidth == 0
        ) {
        // pop-ups ARE blocked
        document.location.href = 'popupsBlocked.htm';
    }
    else {
        // pop-ups are NOT blocked
        cope.PopupTest.testWindow.close();
    }

위의 ‘about : blank’트릭이 더 이상 크롬에서 작동하지 않기 때문에 outerHeight 및 outerWidth는 크롬 용입니다.


답변

여기에 제공된 답변을 복사 / 붙여 넣기하겠습니다 : https://stackoverflow.com/a/27725432/892099 by DanielB. 크롬 40에서 작동하며 매우 깨끗합니다. 더러운 해킹이나 대기가 필요하지 않습니다.

function popup(urlToOpen) {
  var popup_window=window.open(urlToOpen,"myWindow","toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=yes, resizable=yes, copyhistory=yes, width=400, height=400");
  try {
    popup_window.focus();
  }
  catch (e) {
    alert("Pop-up Blocker is enabled! Please add this site to your exception list.");
  }
}


답변

방법에 대한 Promise접근?

const openPopUp = (...args) => new Promise(s => {
  const win = window.open(...args)
  if (!win || win.closed) return s()
  setTimeout(() => (win.innerHeight > 0 && !win.closed) ? s(win) : s(), 200)
})

그리고 클래식처럼 사용할 수 있습니다. window.open

const win = await openPopUp('popuptest.htm', 'popuptest')
if (!win) {
  // popup closed or blocked, handle alternative case
}

을 반환하는 대신 약속을 실패하도록 코드를 변경할 수 있습니다 .이 경우 보다 제어 흐름이 더 쉽다고 undefined생각했습니다 .iftry / catch