브라우저 탭에 포커스가 있는지 감지


149

탭에 포커스가 있음을 감지하는 신뢰할 수있는 브라우저 간 방법이 있습니까?

시나리오는 주가에 대해 정기적으로 설문 조사를하는 애플리케이션이 있고, 페이지에 초점이 맞지 않으면 설문 조사를 중단하고 모든 사람들이 교통 소음을 줄일 수 있습니다. 특히 사람들이 다른 포트폴리오를 가진 여러 탭을 여는 팬이라면 더욱 그렇습니다.

인가 window.onblur및 window.onfocus이에 대한 옵션?


답변:


127

예, window.onfocus그리고 window.onblur당신의 시나리오에 대해 작동합니다 :

http://www.thefutureoftheweb.com/blog/detect-browser-window-focus


3
이것의 onfocusin / onfocusout 측면과 사용자에게 일시 중지되었음을 알려주는 메모는 실제로 좋은 메모입니다. 감사.
— Fenton

7
이 방법으로 페이지를로드 할 때 페이지를 활성화 또는 비활성화하는 것을 구분할 수 없습니다.
— pimvdb

@SteveFenton-크로스 브라우저입니다. onfocus언급 한 이벤트가 IE 전용입니다. 왜 이것이 좋은 메모인지 고려할 수 없습니다 ..
— vsync

1
@vsync-링크 된 기사를 읽으면 'onfocusin'과 'onfocus'를 모두 사용 하는 것을 볼 수 있습니다.
— Fenton

둘 사이의 차이점을 적어도 언급 할 수 있습니까?
— Lenar Hoyt

53

중요 편집 : 이 답변은 구식입니다. 그것을 작성한 이후 Visibility API ( mdn , example , spec )가 도입되었습니다. 이 문제를 해결하는 더 좋은 방법입니다.


var focused = true;

window.onfocus = function() {
    focused = true;
};
window.onblur = function() {
    focused = false;
};

AFAIK, focus그리고 blur모든에 ... 모두 지원됩니다. ( http://www.quirksmode.org/dom/events/index.html 참조 )


2
이 모든 솔루션을 사용하면 자바 스크립트가 완전히로드되기 전에 사용자가 탭을 변경 할 위험이 있으므로 초점을 맞출 잘못된 값이 할당됩니다. 그 주위에 좋은 방법이 있는지 확실하지 않습니다.
— JayD3e

업데이트 링크는 내가 찾던 것입니다. 추가해 주셔서 감사합니다!
— webLacky3rdClass

문제는 구체적으로 페이지에 초점이 있는지 여부를 감지하는 것인데, 이는 페이지가 보이는지 감지하는 것과 다릅니다. 여러 페이지를 동시에 (다른 창에서) 볼 수 있지만 한 페이지 만 포커스를 가질 수 있습니다. 필요에 맞는 기술을 사용하되 그 차이를 알고 있어야합니다.
— jaredjacobs

1
더 큰 응용 프로그램에서 다른 이벤트 리스너를 재정의 할 위험이 있으므로 위험한 솔루션입니다. 대신 다음 답변을 따라야합니다. stackoverflow.com/a/21935031/549503
— mmmeff

51

이 문제를 검색하는 동안 Page Visibility API를 사용해야한다는 권장 사항을 찾았습니다 . 대부분의 최신 브라우저는 http://caniuse.com/#feat=pagevisibility에 따라이 API를 지원합니다 .

다음은 실제 예제입니다 ( 이 코드 조각 에서 파생 됨 ).

$(document).ready(function() {
  var hidden, visibilityState, visibilityChange;

  if (typeof document.hidden !== "undefined") {
    hidden = "hidden", visibilityChange = "visibilitychange", visibilityState = "visibilityState";
  } else if (typeof document.msHidden !== "undefined") {
    hidden = "msHidden", visibilityChange = "msvisibilitychange", visibilityState = "msVisibilityState";
  }

  var document_hidden = document[hidden];

  document.addEventListener(visibilityChange, function() {
    if(document_hidden != document[hidden]) {
      if(document[hidden]) {
        // Document hidden
      } else {
        // Document shown
      }

      document_hidden = document[hidden];
    }
  });
});

업데이트 : 위의 예제는 Gecko 및 WebKit 브라우저의 접두사 속성을 사용했지만 이전에는 접두사가없는 Page Visibility API를 제공했기 때문에 해당 구현을 제거했습니다. IE10과 호환되도록 Microsoft 전용 접두사를 유지했습니다.


공급 업체 접두사가 이것에서 나올 때, 아마도 전환 할 것입니다!
— Fenton 2019

공식 W3C 권장 사항 (2013 년 10 월 29 일자)이 있기 때문에이 문제에 대한 실제 문제는 공급 업체 접두사가 아닙니다. 경우에 따라 문제는 페이지 가시성 API가 IE10 이상에서 지원된다는 것입니다. IE9를 지원해야한다면 다른 접근법을 찾아야합니다…
— Ilija

이것은 모든 최신 브라우저에서 올바른 방법입니다. +1
— Ajedi32

이러한 공급 업체 접두사도 필요합니까? MDN과 CanIUse에 따르면 버전 32부터 Chrome 또는 17에서 Firefox에서는 필요하지 않았으며 IE에서는 필요하지 않았습니다.
— Ajedi32

@ Ajedi32 감사합니다. 나는 여전히 관련성이 있는지, 그리고 지금 무엇을 남길 수 있는지 확인하기 위해 몇 가지 테스트와 파기를해야합니다.
— Ilija

37

아무도 언급하지 않은 것을보고 놀랐습니다. document.hasFocus

if (document.hasFocus()) console.log('Tab is active')

MDN에 자세한 정보가 있습니다.


나를 위해 작동합니다 (Chrome 및 Firefox에서 테스트). 허용 된 답변 (onfocus / onblur)이 작동 하지 않습니다
— harmv

정답은 다시 맨 아래에 있습니다. StackOverflow로가는 길!
— 10 월 11

정말로 이것이 완벽한 답이 아닌가? 누구나 단점이 있습니까?
— gaspar

2
이것의 유일한 단점은 탭이 iframe 내에서 초점을 맞추고 있는지 확인하려고하면 부모 페이지에 여전히 초점이 맞지 않을 때 iframe 이로 드 된 경우 실패한다는 것입니다. 이를 다루려면 페이지 가시성 API를 사용해야합니다.
— 이반

29

네, 당신을 위해 일해야합니다. 당신은 저에게이 기술을 이용하는 링크를 발견했습니다. 재미있는 읽을 거리


2
+1-그것은 매우 영리한 속임수입니다. 많은 사람들을 속이는 것을 상상할 수 있습니다.
— Fenton

2
얼마나 독창적이고 악의적 인 공격입니까? 재미있게 읽어 주셔서 감사합니다.
— Voo

4

나는 이것을 이렇게 할 것이다 (참조 http://www.w3.org/TR/page-visibility/ ) :

    window.onload = function() {

        // check the visiblility of the page
        var hidden, visibilityState, visibilityChange;

        if (typeof document.hidden !== "undefined") {
            hidden = "hidden", visibilityChange = "visibilitychange", visibilityState = "visibilityState";
        }
        else if (typeof document.mozHidden !== "undefined") {
            hidden = "mozHidden", visibilityChange = "mozvisibilitychange", visibilityState = "mozVisibilityState";
        }
        else if (typeof document.msHidden !== "undefined") {
            hidden = "msHidden", visibilityChange = "msvisibilitychange", visibilityState = "msVisibilityState";
        }
        else if (typeof document.webkitHidden !== "undefined") {
            hidden = "webkitHidden", visibilityChange = "webkitvisibilitychange", visibilityState = "webkitVisibilityState";
        }


        if (typeof document.addEventListener === "undefined" || typeof hidden === "undefined") {
            // not supported
        }
        else {
            document.addEventListener(visibilityChange, function() {
                console.log("hidden: " + document[hidden]);
                console.log(document[visibilityState]);

                switch (document[visibilityState]) {
                case "visible":
                    // visible
                    break;
                case "hidden":
                    // hidden
                    break;
                }
            }, false);
        }

        if (document[visibilityState] === "visible") {
            // visible
        }

    };  

이 답변이 @Ilija가 제공 한 답변과 어떻게 다른지 설명 할 수 있습니까? 차이가있을 수 있지만 미묘합니다. 그래서 그것이 무엇인지, 왜 다른지 설명해야합니다.
— Fenton

2

크로스 브라우저 jQuery 솔루션! GitHub 에서 제공되는 Raw

재미 있고 사용하기 쉬운!

다음 플러그인은 다양한 버전의 IE, Chrome, Firefox, Safari 등의 표준 테스트를 거쳐 선언 된 메소드를 설정합니다. 또한 다음과 같은 문제를 다룹니다.

  • onblur | .blur / onfocus | .focus " 중복 "호출
  • 단어와 같은 대체 앱을 선택하여 초점을 잃는 창
    • 이것은 은행 페이지가 열려 있고 onblur 이벤트가 페이지를 마스크하도록 지시하면 계산기를 열면 더 이상 페이지를 볼 수 없기 때문에 바람직하지 않습니다.
  • 페이지로드시 트리거되지 않음

: 사용은 간단하다 '스크롤 아래로 실행 코드 조각 '

$.winFocus(function(event, isVisible) {
    console.log("Combo\t\t", event, isVisible);
});

//  OR Pass False boolean, and it will not trigger on load,
//  Instead, it will first trigger on first blur of current tab_window
$.winFocus(function(event, isVisible) {
    console.log("Combo\t\t", event, isVisible);
}, false);

//  OR Establish an object having methods "blur" & "focus", and/or "blurFocus"
//  (yes, you can set all 3, tho blurFocus is the only one with an 'isVisible' param)
$.winFocus({
    blur: function(event) {
        console.log("Blur\t\t", event);
    },
    focus: function(event) {
        console.log("Focus\t\t", event);
    }
});

//  OR First method becoms a "blur", second method becoms "focus"!
$.winFocus(function(event) {
    console.log("Blur\t\t", event);
},
function(event) {
    console.log("Focus\t\t", event);
});

/*    Begin Plugin    */
;;(function($){$.winFocus||($.extend({winFocus:function(){var a=!0,b=[];$(document).data("winFocus")||$(document).data("winFocus",$.winFocus.init());for(x in arguments)"object"==typeof arguments[x]?(arguments[x].blur&&$.winFocus.methods.blur.push(arguments[x].blur),arguments[x].focus&&$.winFocus.methods.focus.push(arguments[x].focus),arguments[x].blurFocus&&$.winFocus.methods.blurFocus.push(arguments[x].blurFocus),arguments[x].initRun&&(a=arguments[x].initRun)):"function"==typeof arguments[x]?b.push(arguments[x]):
"boolean"==typeof arguments[x]&&(a=arguments[x]);b&&(1==b.length?$.winFocus.methods.blurFocus.push(b[0]):($.winFocus.methods.blur.push(b[0]),$.winFocus.methods.focus.push(b[1])));if(a)$.winFocus.methods.onChange()}}),$.winFocus.init=function(){$.winFocus.props.hidden in document?document.addEventListener("visibilitychange",$.winFocus.methods.onChange):($.winFocus.props.hidden="mozHidden")in document?document.addEventListener("mozvisibilitychange",$.winFocus.methods.onChange):($.winFocus.props.hidden=
"webkitHidden")in document?document.addEventListener("webkitvisibilitychange",$.winFocus.methods.onChange):($.winFocus.props.hidden="msHidden")in document?document.addEventListener("msvisibilitychange",$.winFocus.methods.onChange):($.winFocus.props.hidden="onfocusin")in document?document.onfocusin=document.onfocusout=$.winFocus.methods.onChange:window.onpageshow=window.onpagehide=window.onfocus=window.onblur=$.winFocus.methods.onChange;return $.winFocus},$.winFocus.methods={blurFocus:[],blur:[],focus:[],
exeCB:function(a){$.winFocus.methods.blurFocus&&$.each($.winFocus.methods.blurFocus,function(b,c){this.apply($.winFocus,[a,!a.hidden])});a.hidden&&$.winFocus.methods.blur&&$.each($.winFocus.methods.blur,function(b,c){this.apply($.winFocus,[a])});!a.hidden&&$.winFocus.methods.focus&&$.each($.winFocus.methods.focus,function(b,c){this.apply($.winFocus,[a])})},onChange:function(a){var b={focus:!1,focusin:!1,pageshow:!1,blur:!0,focusout:!0,pagehide:!0};if(a=a||window.event)a.hidden=a.type in b?b[a.type]:
document[$.winFocus.props.hidden],$(window).data("visible",!a.hidden),$.winFocus.methods.exeCB(a);else try{$.winFocus.methods.onChange.call(document,new Event("visibilitychange"))}catch(c){}}},$.winFocus.props={hidden:"hidden"})})(jQuery);
/*    End Plugin      */

// Simple example
$(function() {
	$.winFocus(function(event, isVisible) {
		$('td tbody').empty();
		$.each(event, function(i) {
			$('td tbody').append(
				$('<tr />').append(
					$('<th />', { text: i }),
					$('<td />', { text: this.toString() })
				)
			)
		});
		if (isVisible) 
			$("#isVisible").stop().delay(100).fadeOut('fast', function(e) {
				$('body').addClass('visible');
				$(this).stop().text('TRUE').fadeIn('slow');
			});
		else {
			$('body').removeClass('visible');
			$("#isVisible").text('FALSE');
		}
	});
})
body { background: #AAF; }
table { width: 100%; }
table table { border-collapse: collapse; margin: 0 auto; width: auto; }
tbody > tr > th { text-align: right; }
td { width: 50%; }
th, td { padding: .1em .5em; }
td th, td td { border: 1px solid; }
.visible { background: #FFA; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<h3>See Console for Event Object Returned</h3>
<table>
    <tr>
        <th><p>Is Visible?</p></th>
        <td><p id="isVisible">TRUE</p></td>
    </tr>
    <tr>
        <td colspan="2">
            <table>
                <thead>
                    <tr>
                        <th colspan="2">Event Data <span style="font-size: .8em;">{ See Console for More Details }</span></th>
                    </tr>
                </thead>
                <tbody></tbody>
            </table>
        </td>
    </tr>
</table>


플러그인에 대해 코드를 최소화하지 않아야합니다.
— Patrick Desjardins

@PatrickDesjardins 예. 이번 주말에 다른 것들과 함께 계획하십시오. 나는? 내가 가진 많은 것들에 대해 요점을 밝히십시오. github의 Jdmckinstry. 요점에 추가 될 때 이와 같은 이전 답변에 대한 링크를 추가합니다.
— SpYk3HH

"워드"또는 "계산기"와 같은 다른 앱으로 전환 할 때 페이지의 포커스를 잃고 싶다면 어떻게해야합니까?
— Benas

@Benas 잘못되었을 수도 있지만 jQuery(window).blur/focus, 이것이 매우 기본적 인 기본 기능이라고 생각합니다. 많은 사람들이 원하지 않았기 때문에이 플러그인을 만든 이유 중 하나입니다. 이 플러그인은 jQuery가 제공하지 않는 기능을 제공하기위한 것입니다.
— SpYk3HH
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.