브라우저 창이 현재 활성화되어 있지 않은지를 감지하는 방법이 있습니까?


585

정기적으로 활동하는 JavaScript가 있습니다. 사용자가 사이트를보고 있지 않은 경우 (예 : 창 또는 탭에 포커스가없는 경우) 실행하지 않는 것이 좋습니다.

JavaScript를 사용하여이를 수행 할 수있는 방법이 있습니까?

내 기준점 : 사용중인 창이 활성화되어 있지 않으면 Gmail 채팅에서 소리가납니다.


8
아래의 답변에 만족하지 않는 사람들의 확인을 위해 requestAnimationFrameAPI를, 또는 주파수가있는 현대적인 기능을 사용하여 setTimeout/ setInterval(예를 들어, 크롬에서 1 초) 윈도우가 보이지 않을 때 감소한다.
Rob W

2
document.body.onblur = function (e) {console.log ( 'lama');}은 포커스가없는 요소에 대해 작동했습니다.
WhyMe

2
참조 이 답변을 사용하는 W3C 페이지 가시성 API는, 다시 하락하는 크로스 브라우저 호환 솔루션 blur/ focus브라우저에서하는 것은 지원하지 않습니다.
Mathias Bynens

2
아래 답변의 80 %는 이 질문에 대한 답변이 아닙니다 . 이 질문은 현재 활성화 되지 않았지만 아래의 많은 답변이 보이지 않는 것에 관한 것입니다.이 질문에 대한 답변이 아닙니다. 그것들은 틀림없이 "답이 아님"으로 표시되어야한다
gman

답변:


691

원래이 답변을 작성한 이후 W3C 덕분에 새로운 사양이 권장 상태에 도달했습니다 . 페이지 가시성 API (에 MDN는 ) 이제 페이지가 사용자에게 숨겨져 때 우리가보다 정확하게 감지 할 수 있습니다.

document.addEventListener("visibilitychange", onchange);

현재 브라우저 지원 :

  • 크롬 13+
  • Internet Explorer 10 이상
  • Firefox 10 이상
  • Opera 12.10+ [ 노트 읽기 ]

다음 코드는 호환되지 않는 브라우저에서 덜 안정적인 흐림 / 포커스 방법으로 대체됩니다.

(function() {
  var hidden = "hidden";

  // Standards:
  if (hidden in document)
    document.addEventListener("visibilitychange", onchange);
  else if ((hidden = "mozHidden") in document)
    document.addEventListener("mozvisibilitychange", onchange);
  else if ((hidden = "webkitHidden") in document)
    document.addEventListener("webkitvisibilitychange", onchange);
  else if ((hidden = "msHidden") in document)
    document.addEventListener("msvisibilitychange", onchange);
  // IE 9 and lower:
  else if ("onfocusin" in document)
    document.onfocusin = document.onfocusout = onchange;
  // All others:
  else
    window.onpageshow = window.onpagehide
    = window.onfocus = window.onblur = onchange;

  function onchange (evt) {
    var v = "visible", h = "hidden",
        evtMap = {
          focus:v, focusin:v, pageshow:v, blur:h, focusout:h, pagehide:h
        };

    evt = evt || window.event;
    if (evt.type in evtMap)
      document.body.className = evtMap[evt.type];
    else
      document.body.className = this[hidden] ? "hidden" : "visible";
  }

  // set the initial state (but only if browser supports the Page Visibility API)
  if( document[hidden] !== undefined )
    onchange({type: document[hidden] ? "blur" : "focus"});
})();

onfocusin하고 onfocusout있다 IE 9에 필요한 낮출 모든 다른 사람을 활용하면서, onfocus그리고 onblur아이폰 OS, 용도를 제외 onpageshow하고 onpagehide.


1
@bellpeace : IE 전파해야 focusin하고 focusout상단 창에 iframe을에서. 최신 브라우저의 경우 각 iframe 객체 의 focusblur이벤트 만 처리하면 window됩니다. 방금 추가 한 업데이트 된 코드를 사용해야합니다.이 코드는 최신 브라우저에서 해당 사례를 다루는 것입니다.
Andy E

3
@JulienKronegg : 그렇기 때문에 제 답변에는 원래 답변을 작성한 후 작업 초안 상태에 들어간 페이지 가시성 API가 언급되어 있습니다. 포커스 / 블러 방법은 구형 브라우저에 제한된 기능을 제공합니다. 답변에서와 같이 다른 이벤트에 바인딩하는 것은 이것보다 더 많은 것을 다루지 않으며 행동 차이의 위험이 더 큽니다 (예 : 커서 아래에 창이 팝업 될 때 IE가 마우스 아웃을 시작하지 않음). 페이지 비 활동으로 인해 업데이트가 덜 빈번 할 수 있음을 나타내는 메시지 또는 아이콘을 사용자에게 표시하는 것이 더 적절한 조치입니다.
Andy E

6
@AndyE 크롬 에서이 솔루션을 시도했습니다. 탭을 변경하면 작동하지만 창을 변경하면 작동하지 않습니다 (ALT + Tab). 그래야합니까? 여기에 바이올린입니다 - jsfiddle.net/8a9N6/17
토니 Lâmpada

2
@ Helodorodor : 지금은 대답의 코드를 최소한으로 유지하고 싶습니다. 구현자가 몸에 클래스를 설정하는 것을 피하고 완전히 다른 동작 (예 : 타이머 중지 및 시작)을 원할 수 있기 때문에 잘라 내기 및 붙여 넣기 완벽한 솔루션이 아닙니다.
Andy E

8
@AndyE 사용자가 탭을 변경하거나 창을 최소화 / 최대화 한 경우에만 솔루션이 작동하는 것 같습니다. 그러나 사용자가 탭을 활성 상태로두면 onchange 이벤트가 트리거되지 않지만 작업 표시 줄에서 다른 프로그램을 최대화합니다. 해당 시나리오에 대한 솔루션이 있습니까? 감사!
user1491636

132

jQuery를 사용하면됩니다.

$(window).blur(function(){
  //your code here
});
$(window).focus(function(){
  //your code
});

또는 적어도 그것은 나를 위해 일했습니다.


1
나를 위해이 전화는 iframe에서 두 번
msangel

Firefox에서는 같은 페이지에서 firebug 콘솔 내부를 클릭하면 window포커스가 느슨해 지지만 의도에 따라 필요하지 않을 수도 있습니다.
Majid Fouladpour 7:27에

21
더 이상 최신 버전의 최신 브라우저에서는 작동하지 않습니다. 승인 된 답변 (페이지 가시성 API)
Jon z

이 솔루션은 iPad에서 작동하지 않습니다 "pageshow"이벤트를 사용하십시오
ElizaS

페이지가로드되면 BLUR 및 FOCUS가 모두 해제됩니다. 내 페이지에서 새 창을 열면 아무 일도 일어나지 않지만 새 창을 닫으면 두 이벤트가 모두 종료됩니다
./(IE8

49

사용자가 HTML 페이지를 볼 수 있는지 판별하는 데 사용되는 3 가지 일반적인 방법이 있지만 그 중 어느 것도 완벽하게 작동하지는 않습니다.

  • W3C 페이지 가시성 API는 이 작업을 수행 할 예정이다 (파이어 폭스 10, MSIE (10), 크롬 13부터 지원). 그러나이 API는 브라우저 탭이 완전히 재정의 된 경우 (예 : 사용자가 한 탭에서 다른 탭으로 변경하는 경우)에만 이벤트를 발생시킵니다. 가시성을 100 % 정확도로 확인할 수없는 경우 API는 이벤트를 발생시키지 않습니다 (예 : 다른 애플리케이션으로 전환하기 위해 Alt + Tab).

  • 사용 초점 / 흐림 기반의 방법은 당신에게 거짓 양성을 많이 제공합니다. 예를 들어, 사용자가 브라우저 창 위에 작은 창을 표시하면 브라우저 창에서 포커스를 잃지 onblur만 ( 상승) 사용자는 여전히 볼 수 있으므로 여전히 새로 고쳐야합니다. http://javascript.info/tutorial/focus 도 참조하십시오

  • 사용자 활동 (마우스 이동, 클릭, 키 입력) 에 의존 하면 오 탐지가 많이 발생합니다. 위와 동일한 경우 또는 사용자가 비디오를보고 있다고 생각하십시오.

위에서 설명한 불완전한 동작을 개선하기 위해 W3C Visibility API의 3 가지 방법을 조합 한 다음 오 탐지율을 줄이기 위해 포커스 / 블러 및 사용자 활동 방법을 사용합니다. 이를 통해 다음과 같은 이벤트를 관리 할 수 ​​있습니다.

  • 브라우저 탭을 다른 것으로 변경 (W3C 페이지 가시성 API 덕분에 100 % 정확도)
  • Alt + Tab으로 인해 다른 창에 의해 잠재적으로 숨겨져있는 페이지
  • 잠재적으로 HTML 페이지에 초점을 맞추지 않은 사용자주의 (확률 = 100 % 정확하지 않음)

작동 방식 : 문서가 포커스를 잃을 때, 윈도우의 표시 여부를 결정하기 위해 문서의 사용자 활동 (예 : 마우스 이동)이 모니터링됩니다. 페이지 가시성 확률은 페이지에서 마지막 사용자 활동 시간에 반비례합니다. 사용자가 문서에서 오랫동안 활동을하지 않으면 페이지가 보이지 않을 가능성이 높습니다. 아래 코드는 W3C 페이지 가시성 API를 모방합니다. 동일한 방식으로 작동하지만 오 탐지율이 작습니다. 멀티 브라우저 (Firefox 5, Firefox 10, MSIE 9, MSIE 7, Safari 5, Chrome 9에서 테스트) 이점이 있습니다.

    <div id = "x"> </ div>

    <스크립트>
    / **
    주어진 객체의 이벤트에 핸들러를 등록합니다.
    @param obj 이벤트를 발생시킬 객체
    @param ev 이벤트 유형을 입력하십시오 : click, keypress, mouseover, ...
    @param fn 이벤트 핸들러 함수
    @param isCapturing 이벤트 모드 설정 (true = 캡처 이벤트, false = 버블 링 이벤트)
    이벤트 핸들러가 올바르게 첨부 된 경우 @return
    * /
    addEvent 함수 (obj, evType, fn, isCapturing) {
      (isCapturing == null) 인 경우 isCapturing = false; 
      if (obj.addEventListener) {
        // Firefox
        obj.addEventListener (evType, fn, isCapturing);
        true를 반환;
      } 그렇지 않으면 (obj.attachEvent) {
        // MSIE
        var r = obj.attachEvent ( 'on'+ evType, fn);
        리턴 r;
      } else {
        거짓을 반환;
      }
    }

    // 잠재적 페이지 가시성 변경에 등록
    addEvent (문서, "잠재적 가시성 변경", 함수 (이벤트) {
      document.getElementById ( "x"). innerHTML + = "potentialVisilityChange : potentialHidden ="+ document.potentialHidden + ", document.potentiallyHiddenSince ="+ document.potentiallyHiddenSince + "s <br>";
    });

    // W3C 페이지 가시성 API에 등록
    var hidden = 널;
    var visibleChange = null;
    if (typeof document.mozHidden! == "undefined") {
      hidden = "mozHidden";
      visibleChange = "mozvisibilitychange";
    } else if (typeof document.msHidden! == "undefined") {
      hidden = "msHidden";
      visibleChange = "msvisibilitychange";
    } else if (typeof document.webkitHidden! == "undefined") {
      hidden = "webkitHidden";
      visibleChange = "webkitvisibilitychange";
    } else if (typeof document.hidden! == "hidden") {
      hidden = "숨겨진";
      visibleChange = "visibilitychange";
    }
    if (hidden! = null && visibleChange! = null) {
      addEvent (문서, 가시성 변경, 함수 (이벤트) {
        document.getElementById ( "x"). innerHTML + = visibilityChange + ":"+ hidden + "="+ document [hidden] + "<br>";
      });
    }


    var potentialPageVisibility = {
      pageVisibilityChangeThreshold : 3 * 3600, // 초 단위
      init : 함수 () {
        함수 setAsNotHidden () {
          var dispatchEventRequired = document.potentialHidden;
          document.potentialHidden = false;
          document.potentiallyHiddenSince = 0;
          if (dispatchEventRequired) dispatchPageVisibilityChangeEvent ();
        }

        함수 initPotentiallyHiddenDetection () {
          if (! hasFocusLocal) {
            // 창에 포커스가 없습니다 => 창에서 사용자 활동을 확인하십시오.
            lastActionDate = 새 날짜 ();
            if (timeoutHandler! = null) {
              clearTimeout (timeoutHandler);
            }
            timeoutHandler = setTimeout (checkPageVisibility, potentialPageVisibility.pageVisibilityChangeThreshold * 1000 + 100); // Firefox에서 반올림 문제를 피하기 위해 + 100ms
          }
        }

        dispatchPageVisibilityChangeEvent () {함수
          unifiedVisilityChangeEventDispatchAllowed = 거짓;
          var evt = document.createEvent ( "Event");
          evt.initEvent ( "potentialvisilitychange", true, true);
          document.dispatchEvent (evt);
        }

        function checkPageVisibility () {
          var potentialHiddenDuration = (hasFocusLocal || lastActionDate == null? 0 : Math.floor ((새 날짜 () .getTime ()-lastActionDate.getTime ()) / 1000));
                                        document.potentiallyHiddenSince = potentialHiddenDuration;
          if (potentialHiddenDuration> = potentialPageVisibility.pageVisibilityChangeThreshold &&! document.potentialHidden) {
            // 페이지 가시성 변경 임계 값 급증 => 짝수 올리기
            document.potentialHidden = true;
            dispatchPageVisibilityChangeEvent ();
          }
        }

        var lastActionDate = 널;
        var hasFocusLocal = true;
        var hasMouseOver = true;
        document.potentialHidden = false;
        document.potentiallyHiddenSince = 0;
        var timeoutHandler = null;

        addEvent (문서, "pageshow", 함수 (event) {
          document.getElementById ( "x"). innerHTML + = "pageshow / doc : <br>";
        });
        addEvent (문서, "pagehide", 함수 (event) {
          document.getElementById ( "x"). innerHTML + = "pagehide / doc : <br>";
        });
        addEvent (창, "pageshow", 함수 (event) {
          document.getElementById ( "x"). innerHTML + = "pageshow / win : <br>"; // 페이지가 처음 표시 될 때 발생합니다.
        });
        addEvent (창, "pagehide", 함수 (event) {
          document.getElementById ( "x"). innerHTML + = "pagehide / win : <br>"; // 제기되지 않음
        });
        addEvent (문서, "mousemove", 함수 (event) {
          lastActionDate = 새 날짜 ();
        });
        addEvent (문서, "마우스 오버", 함수 (이벤트) {
          hasMouseOver = true;
          setAsNotHidden ();
        });
        addEvent (문서, "마우스 아웃", 함수 (이벤트) {
          hasMouseOver = 거짓;
          initPotentiallyHiddenDetection ();
        });
        addEvent (창, "흐림", 함수 (이벤트) {
          hasFocusLocal = false;
          initPotentiallyHiddenDetection ();
        });
        addEvent (창, "포커스", 함수 (이벤트) {
          hasFocusLocal = true;
          setAsNotHidden ();
        });
        setAsNotHidden ();
      }
    }

    potentialPageVisibility.pageVisibilityChangeThreshold = 4; // 테스트를위한 4 초
    potentialPageVisibility.init ();
    </ script>

현재 오 탐지없이 작동하는 크로스 브라우저 솔루션이 없으므로 웹 사이트에서 주기적 활동을 비활성화하는 것에 대해 두 번 생각하는 것이 좋습니다.


undefined 키워드 대신 'undefined'문자열에 엄격한 비교 연산자를 사용하지 않으면 위 코드에서 오 탐지가 발생합니까?
Jonathon

@ kiran : 실제로 Alt + Tab으로 작업하고 있습니다. Alt + Tab을 수행 할 때 더 작은 창으로 전환 할 수 있으므로 페이지가 완전히 숨겨져 있다고 보장 할 수 없으므로 페이지가 숨겨져 있는지 확인할 수 없습니다. 이것이 바로 "잠재적으로 숨겨진"개념을 사용하는 이유입니다 (예 : 임계 값이 4 초로 설정되어 있으므로 Alt + Tab을 사용하여 4 초 이상 동안 다른 창으로 전환해야합니다). 그러나 귀하의 의견은 답변이 명확하지 않다는 것을 보여 주므로 다시 말한 것입니다.
Julien Kronegg 2016

@JulienKronegg 이것이 최선의 해결책이라고 생각합니다. 그러나, 위의 코드는 매우 리팩토링과 추상화 일부를 필요로한다. 왜 그것을 GitHub에 업로드하고 커뮤니티가 리팩토링하도록합니까?
Jacob

1
@Jacob 나는 당신이 내 솔루션을 좋아해서 기쁘다. 직접 GitHub 프로젝트로 홍보하십시오. 라이센스 Creative Commons BY creativecommons.org/licenses/by/4.0로
Julien Kronegg

26

GitHub에는 깔끔한 라이브러리가 있습니다 :

https://github.com/serkanyersen/ifvisible.js

예:

// If page is visible right now
if( ifvisible.now() ){
  // Display pop-up
  openPopUp();
}

내가 가지고있는 모든 브라우저에서 버전 1.0.1을 테스트했으며 다음과 함께 작동하는지 확인할 수 있습니다.

  • IE9, IE10
  • FF 26.0
  • 크롬 34.0

... 그리고 아마도 모든 최신 버전 일 것입니다.

다음과 완벽하게 작동하지 않습니다.

  • IE8-항상 탭 / 창이 활성화되어 있음을 나타냅니다 ( .now()항상 true나에게 반환 ).

수락 된 답변으로 인해 IE9에서 문제가 발생했습니다. 이 라이브러리는 훌륭하게 작동합니다.
Tom Teman

20

사용 : 페이지 가시성 API

document.addEventListener( 'visibilitychange' , function() {
    if (document.hidden) {
        console.log('bye');
    } else {
        console.log('well back');
    }
}, false );

사용해도 되나요 ? http://caniuse.com/#feat=pagevisibility


문제는 페이지 가시성에 관한 것이 아닙니다. 그것은 활성화 / 비활성화되지 않습니다
gman

나는 OP가 ide의 기능에 대해 이야기하고 있지 않다고 생각합니다
l2aelba

1
나는 ide에 대해서도 이야기하고 있지 않습니다. 다른 앱에 대한 alt-tabbing / cmd-tabbing에 대해 이야기하고 있습니다. 갑자기 페이지가 활성화되지 않았습니다. 페이지 가시성 API는 페이지가 활성화되어 있지 않은지 알 수 없으며 페이지가 보이지 않는지 알려줍니다.
gman

18

내 앱에 대한 혜성 채팅을 만들고 다른 사용자로부터 메시지를 받으면 다음을 사용합니다.

if(new_message){
    if(!document.hasFocus()){
        audio.play();
        document.title="Have new messages";
    }
    else{
        audio.stop();
        document.title="Application Name";
    } 
}

2
IE6를 지원하는 가장 깨끗한 솔루션
Paul Cooper

4
document.hasFocus()가장 깨끗한 방법입니다. 가시성 API 또는 이벤트 기반을 사용하거나 다양한 수준의 사용자 활동 / 활동 부족을 찾는 다른 모든 방법은 지나치게 복잡 해져서 복잡한 사례와 허점으로 가득 차게됩니다. 간단한 간격으로 놓고 결과가 변경되면 맞춤 이벤트를 발생시킵니다. 예 : jsfiddle.net/59utucz6/1
danatcofo

1
효율적이며 다른 솔루션과 달리 다른 브라우저 탭이나 창, 심지어 다른 응용 프로그램으로 전환 할 때 올바른 피드백을 제공합니다.
ow3n

의심 할 여지없이, 그 가장 깨끗한 방법으로하지만, 파이어 폭스에서 작동하지 않습니다
hardik chugh

1
Chrome 개발자 도구를 열면 document.hasFocus ()가 false와 같습니다. 또는 브라우저 상단 패널을 클릭하더라도 마찬가지입니다. 내가 아니에요 확인이 솔루션 등 비디오, 애니메이션을 일시에 적합
tylik

16

커뮤니티 위키 답변을 사용하기 시작했지만 Chrome에서 Alt-Tab 이벤트를 감지하지 못한다는 것을 깨달았습니다. 사용 가능한 첫 번째 이벤트 소스를 사용하기 때문이며,이 경우 페이지 가시성 API이므로 Chrome에서는 자동 태핑을 추적하지 않는 것 같습니다.

나는 추적 유지하기 위해 스크립트를 조금 수정하기로 결정 모든 페이지 포커스가 변경 가능한 이벤트를. 드롭 할 수있는 기능은 다음과 같습니다.

function onVisibilityChange(callback) {
    var visible = true;

    if (!callback) {
        throw new Error('no callback given');
    }

    function focused() {
        if (!visible) {
            callback(visible = true);
        }
    }

    function unfocused() {
        if (visible) {
            callback(visible = false);
        }
    }

    // Standards:
    if ('hidden' in document) {
        document.addEventListener('visibilitychange',
            function() {(document.hidden ? unfocused : focused)()});
    }
    if ('mozHidden' in document) {
        document.addEventListener('mozvisibilitychange',
            function() {(document.mozHidden ? unfocused : focused)()});
    }
    if ('webkitHidden' in document) {
        document.addEventListener('webkitvisibilitychange',
            function() {(document.webkitHidden ? unfocused : focused)()});
    }
    if ('msHidden' in document) {
        document.addEventListener('msvisibilitychange',
            function() {(document.msHidden ? unfocused : focused)()});
    }
    // IE 9 and lower:
    if ('onfocusin' in document) {
        document.onfocusin = focused;
        document.onfocusout = unfocused;
    }
    // All others:
    window.onpageshow = window.onfocus = focused;
    window.onpagehide = window.onblur = unfocused;
};

다음과 같이 사용하십시오.

onVisibilityChange(function(visible) {
    console.log('the page is now', visible ? 'focused' : 'unfocused');
});

이 버전을 청취 모든 다른 가시성 이벤트 및 화재 그들 중 하나가 변화를 야기하는 경우 콜백. focusedunfocused핸들러는 다수의 API를 같은 가시성 변경을 잡을 경우 콜백이 여러 번 호출하지 않아야합니다.


예를 들어 Chrome에는 document.hidden및 이 모두 document.webkitHidden있습니다. 포함하지 않는 elseif건설 우리는이 콜백 호출 권리를 얻을 것?
Christiaan Westerbeek

@ChristiaanWesterbeek 좋은 지적입니다, 나는 그것을 생각하지 않았습니다! 이 게시물을 편집 할 수 있다면 계속 진행하겠습니다. :)
Daniel Buckmaster

어이 잠깐만 기다려주세요 : ChristiaanWesterbeek이 제안하고 실제로 @ 1.21Gigawatts가 추가 한 "else"를 추가하는 편집은 좋은 생각처럼 보이지 않습니다 : Daniel의 아이디어를 처음 구입 한 것을 물 리치므로, 모든 지원을 시도해야합니다. 병렬로 메소드. 그리고 focus () 및 unfocused ()는 아무것도 변경되지 않을 때 추가 호출을 억제하므로 콜백이 두 번 호출 될 위험이 없습니다. 우리가 첫 번째 개정으로 되돌려 야 할 것 같습니다.
Louis Semprini 2018 년

@LouisSemprini 그것은 큰 캐치입니다. 코드의 원래 의도를 잊어 버렸습니다! 원본을 복원하고 설명을 추가했습니다!
Daniel Buckmaster

오늘 확인하면 Chrome 78 + macos에서 alt + tab을 감지하지 못합니다.
Hugo Gresse

7

정말 까다 롭습니다. 다음 요구 사항이 주어지면 해결책이없는 것 같습니다.

  • 이 페이지에는 사용자가 제어 할 수없는 iframe이 포함되어 있습니다
  • Tab 변경 (ctrl + tab) 또는 창 변경 (alt + tab)에 의해 트리거되는 변경에 관계없이 가시성 상태 변경을 추적하려고합니다.

이것은 다음과 같은 이유로 발생합니다.

  • 페이지 가시성 API를 사용하면 탭 변경 사항 (iframe을 사용하더라도)을 안정적으로 알 수 있지만 사용자가 창을 변경하는 시점은 알 수 없습니다.
  • iframe에 포커스가없는 한 윈도우 블러 / 포커스 이벤트를 들으면 alt + tab 및 ctrl + tab을 감지 할 수 있습니다.

이러한 제한이 주어지면-페이지 가시성 API-창 흐림 / 포커스-document.activeElement를 결합한 솔루션을 구현할 수 있습니다.

그것은 할 수 있습니다 :

  • 1) 상위 페이지에 초점이있을 때 Ctrl + Tab : 예
  • 2) iframe에 포커스가있는 경우 Ctrl + 탭 : 예
  • 3) 상위 페이지에 초점이있을 때 Alt + Tab : YES
  • 4) iframe에 포커스가있을 때 alt + tab : NO <-bummer

iframe에 포커스가 있으면 흐림 / 포커스 이벤트가 전혀 호출되지 않으며 Alt + Tab에서 Visibility API 페이지가 트리거되지 않습니다.

@AndyE의 솔루션을 기반으로 하고이 (거의 좋은) 솔루션을 https://dl.dropboxusercontent.com/u/2683925/estante-components/visibility_test1.html 에서 구현했습니다 (죄송합니다, JSFiddle에 문제가 있습니다).

이것은 Github에서도 가능합니다 : https://github.com/qmagico/estante-components

이것은 크롬 / 크롬에서 작동합니다. iframe 내용을로드하지 않는 것을 제외하고는 firefox에서 작동합니다 (왜 그런지 아십니까?)

어쨌든, 마지막 문제 (4)를 해결하기 위해 할 수있는 유일한 방법은 iframe에서 블러 / 포커스 이벤트를 듣는 것입니다. iframe을 제어 할 수있는 경우 postMessage API를 사용하여이를 수행 할 수 있습니다.

https://dl.dropboxusercontent.com/u/2683925/estante-components/visibility_test2.html

나는 여전히 충분한 브라우저로 이것을 테스트하지 않았습니다. 이것이 작동하지 않는 위치에 대한 자세한 정보를 찾으면 아래 의견에 알려주십시오.


내 테스트에서는 IE9, IE10 및 Android의 Chrome에서도 작동했습니다.
Tony Lâmpada

1
- 아이 패드는 완전히 다른 솔루션이 필요 보인다 stackoverflow.com/questions/4940657/...
토니 Lâmpada

3
이 모든 링크는 404입니다 :(
Daniel Buckmaster

6
var visibilityChange = (function (window) {
    var inView = false;
    return function (fn) {
        window.onfocus = window.onblur = window.onpageshow = window.onpagehide = function (e) {
            if ({focus:1, pageshow:1}[e.type]) {
                if (inView) return;
                fn("visible");
                inView = true;
            } else if (inView) {
                fn("hidden");
                inView = false;
            }
        };
    };
}(this));

visibilityChange(function (state) {
    console.log(state);
});

http://jsfiddle.net/ARTsinn/JTxQY/


5

이것은 크롬 67, 파이어 폭스 67,

if(!document.hasFocus()) {
    // do stuff
}

3

당신은 사용할 수 있습니다 :

(function () {

    var requiredResolution = 10; // ms
    var checkInterval = 1000; // ms
    var tolerance = 20; // percent


    var counter = 0;
    var expected = checkInterval / requiredResolution;
    //console.log('expected:', expected);

    window.setInterval(function () {
        counter++;
    }, requiredResolution);

    window.setInterval(function () {
        var deviation = 100 * Math.abs(1 - counter / expected);
        // console.log('is:', counter, '(off by', deviation , '%)');
        if (deviation > tolerance) {
            console.warn('Timer resolution not sufficient!');
        }
        counter = 0;
    }, checkInterval);

})();

3

HTML 5에서는 다음을 사용할 수도 있습니다.

  • onpageshow: 창이 보일 때 실행될 스크립트
  • onpagehide: 창이 숨겨 졌을 때 실행될 스크립트

보다:


2
나는 이것이 BFCache와 관련이 있다고 생각합니다. 사용자가 뒤로 또는 앞으로를 클릭하면 컴퓨터 바탕 화면의 맨 위에있는 페이지와 관련이 없습니다.
nonopolarity

2

이것은 Andy E의 답변에 대한 적응입니다.

예를 들어 30 초마다 페이지를 새로 고치지 만 페이지가 표시되고 포커스가있는 경우에만 작업을 수행합니다.

가시성이 감지되지 않으면 초점 만 사용됩니다.

사용자가 페이지에 초점을 맞추면 즉시 업데이트됩니다.

아약스 호출 후 30 초까지 페이지가 다시 업데이트되지 않습니다.

var windowFocused = true;
var timeOut2 = null;

$(function(){
  $.ajaxSetup ({
    cache: false
  });
  $("#content").ajaxComplete(function(event,request, settings){
       set_refresh_page(); // ajax call has just been made, so page doesn't need updating again for 30 seconds
   });
  // check visibility and focus of window, so as not to keep updating unnecessarily
  (function() {
      var hidden, change, vis = {
              hidden: "visibilitychange",
              mozHidden: "mozvisibilitychange",
              webkitHidden: "webkitvisibilitychange",
              msHidden: "msvisibilitychange",
              oHidden: "ovisibilitychange" /* not currently supported */
          };
      for (hidden in vis) {
          if (vis.hasOwnProperty(hidden) && hidden in document) {
              change = vis[hidden];
              break;
          }
      }
      document.body.className="visible";
      if (change){     // this will check the tab visibility instead of window focus
          document.addEventListener(change, onchange,false);
      }

      if(navigator.appName == "Microsoft Internet Explorer")
         window.onfocus = document.onfocusin = document.onfocusout = onchangeFocus
      else
         window.onfocus = window.onblur = onchangeFocus;

      function onchangeFocus(evt){
        evt = evt || window.event;
        if (evt.type == "focus" || evt.type == "focusin"){
          windowFocused=true; 
        }
        else if (evt.type == "blur" || evt.type == "focusout"){
          windowFocused=false;
        }
        if (evt.type == "focus"){
          update_page();  // only update using window.onfocus, because document.onfocusin can trigger on every click
        }

      }

      function onchange () {
        document.body.className = this[hidden] ? "hidden" : "visible";
        update_page();
      }

      function update_page(){
        if(windowFocused&&(document.body.className=="visible")){
          set_refresh_page(1000);
        }
      }


  })();
  set_refresh_page();
})

function get_date_time_string(){
  var d = new Date();
  var dT = [];
  dT.push(d.getDate());
  dT.push(d.getMonth())
  dT.push(d.getFullYear());
  dT.push(d.getHours());
  dT.push(d.getMinutes());
  dT.push(d.getSeconds());
  dT.push(d.getMilliseconds());
  return dT.join('_');
}

function do_refresh_page(){

// do tasks here

// e.g. some ajax call to update part of the page.

// (date time parameter will probably force the server not to cache)

//      $.ajax({
//        type: "POST",
//        url: "someUrl.php",
//        data: "t=" + get_date_time_string()+"&task=update",
//        success: function(html){
//          $('#content').html(html);
//        }
//      });

}

function set_refresh_page(interval){
  interval = typeof interval !== 'undefined' ? interval : 30000; // default time = 30 seconds
  if(timeOut2 != null) clearTimeout(timeOut2);
  timeOut2 = setTimeout(function(){
    if((document.body.className=="visible")&&windowFocused){
      do_refresh_page();
    }
    set_refresh_page();
  }, interval);
}

초점에 의존 / 흐림 방법은 일을하지 않습니다 (그것은 당신에게 거짓 긍정적를 많이 제공)를 참조 stackoverflow.com/a/9502074/698168
줄리앙 Kronegg

2

jQuery가없는 솔루션 은 3 가지 페이지 상태에 대한 정보를 제공 하는 Visibility.js 를 확인 하십시오.

visible    ... page is visible
hidden     ... page is not visible
prerender  ... page is being prerendered by the browser

setInterval을위한 편리한 래퍼

/* Perform action every second if visible */
Visibility.every(1000, function () {
    action();
});

/* Perform action every second if visible, every 60 sec if not visible */
Visibility.every(1000, 60*1000, function () {
    action();
});

구형 브라우저 (IE <10, iOS <7)에 대한 대체 기능도 제공됩니다


브라우저 지원은 어떻습니까? 크롬, 사파리, 파이어 폭스에서 좋은 결과를 얻었습니다.
Selva Ganapathi

1

약간 더 복잡한 방법은 setInterval()마우스 위치를 확인하고 마지막 확인과 비교하는 데 사용 하는 것 입니다. 마우스가 일정 시간 동안 움직이지 않으면 사용자가 유휴 상태 일 수 있습니다.

이 대신에, 사용자가 유휴 상태 인 경우 이야기의 추가 이점이 바로 윈도우가 활성화되지 않은 경우 검사합니다.

많은 사람들이 지적했듯이, 사용자가 마우스를 사용하지 않거나 비디오를 보거나 그와 비슷한 것을 사용하기 때문에 항상 사용자 또는 브라우저 창이 유휴 상태인지 여부를 확인하는 좋은 방법은 아닙니다. 유휴 상태를 확인하는 한 가지 가능한 방법을 제안하고 있습니다.


30
사용자에게 마우스가없는 한.
user1686 2016 년

@Annan : 그것은 것 codinghorror.com/blog/2007/03/... 지금.
chiborg

사용자가 비디오를 시청하는 경우이 또한 주사위를 재생하지 않습니다
jamiew

onkeypress 또는 기타 유사한 이벤트를 사용하여 타이머를 재설정하고 마우스 이외의 문제를 해결할 수 있습니다. 물론 비디오를 보거나 이미지를 연구하기 위해 페이지를 적극적으로보고있는 사용자에게는 여전히 효과가 없습니다.
joshuahedlund

1

angular.js의 경우, 컨트롤러가 가시성 변화에 반응 할 수 있도록 지시문 (허용 된 답변을 기반으로 함)이 있습니다.

myApp.directive('reactOnWindowFocus', function($parse) {
    return {
        restrict: "A",
        link: function(scope, element, attrs) {
            var hidden = "hidden";
            var currentlyVisible = true;
            var functionOrExpression = $parse(attrs.reactOnWindowFocus);

          // Standards:
          if (hidden in document)
            document.addEventListener("visibilitychange", onchange);
          else if ((hidden = "mozHidden") in document)
            document.addEventListener("mozvisibilitychange", onchange);
          else if ((hidden = "webkitHidden") in document)
            document.addEventListener("webkitvisibilitychange", onchange);
          else if ((hidden = "msHidden") in document)
            document.addEventListener("msvisibilitychange", onchange);
          else if ("onfocusin" in document) {
                // IE 9 and lower:
            document.onfocusin = onshow;
                document.onfocusout = onhide;
          } else {
                // All others:
            window.onpageshow = window.onfocus = onshow;
                window.onpagehide = window.onblur = onhide;
            }

          function onchange (evt) {
                //occurs both on leaving and on returning
                currentlyVisible = !currentlyVisible;
                doSomethingIfAppropriate();
          }

            function onshow(evt) {
                //for older browsers
                currentlyVisible = true;
                doSomethingIfAppropriate();
            }

            function onhide(evt) {
                //for older browsers
                currentlyVisible = false;
                doSomethingIfAppropriate();
            }

            function doSomethingIfAppropriate() {
                if (currentlyVisible) {
                    //trigger angular digest cycle in this scope
                    scope.$apply(function() {
                        functionOrExpression(scope);
                    });
                }
            }
        }
    };

});

다음 예제와 같이 사용할 수 있습니다. <div react-on-window-focus="refresh()">여기서 refresh(), 범위에있는 컨트롤러의 범위에 범위 기능이 있습니다.


0

여기에 견고하고 현대적인 솔루션이 있습니다. (달콤한 👌🏽)

document.addEventListener("visibilitychange", () => {
  console.log( document.hasFocus() )
})

이것은 가시성 이벤트가 시작될 때 트리거하도록 리스너를 설정하여 포커스 또는 블러가 될 수 있습니다.


0

당신이 행동을 할 경우 전체 브라우저 흐림 : 나는 주석으로, 만약 제안 된 이벤트 화재의 브라우저 잃게 초점 없음. 내 생각은 이벤트가 발생하면 루프에서 카운트 업하고 카운터를 재설정하는 것입니다. 카운터가 제한에 도달하면 location.href를 다른 페이지로 보냅니다. dev-tools에서 작업하는 경우에도 발생합니다.

var iput=document.getElementById("hiddenInput");
   ,count=1
   ;
function check(){
         count++;
         if(count%2===0){
           iput.focus();
         }
         else{
           iput.blur();
         }
         iput.value=count;  
         if(count>3){
           location.href="http://Nirwana.com";
         }              
         setTimeout(function(){check()},1000);
}   
iput.onblur=function(){count=1}
iput.onfocus=function(){count=1}
check();

이것은 FF에서 성공적으로 테스트 된 초안입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.