정기적으로 활동하는 JavaScript가 있습니다. 사용자가 사이트를보고 있지 않은 경우 (예 : 창 또는 탭에 포커스가없는 경우) 실행하지 않는 것이 좋습니다.
JavaScript를 사용하여이를 수행 할 수있는 방법이 있습니까?
내 기준점 : 사용중인 창이 활성화되어 있지 않으면 Gmail 채팅에서 소리가납니다.
정기적으로 활동하는 JavaScript가 있습니다. 사용자가 사이트를보고 있지 않은 경우 (예 : 창 또는 탭에 포커스가없는 경우) 실행하지 않는 것이 좋습니다.
JavaScript를 사용하여이를 수행 할 수있는 방법이 있습니까?
내 기준점 : 사용중인 창이 활성화되어 있지 않으면 Gmail 채팅에서 소리가납니다.
답변:
원래이 답변을 작성한 이후 W3C 덕분에 새로운 사양이 권장 상태에 도달했습니다 . 페이지 가시성 API (에 MDN는 ) 이제 페이지가 사용자에게 숨겨져 때 우리가보다 정확하게 감지 할 수 있습니다.
document.addEventListener("visibilitychange", onchange);
현재 브라우저 지원 :
다음 코드는 호환되지 않는 브라우저에서 덜 안정적인 흐림 / 포커스 방법으로 대체됩니다.
(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
.
focusin
하고 focusout
상단 창에 iframe을에서. 최신 브라우저의 경우 각 iframe 객체 의 focus
및 blur
이벤트 만 처리하면 window
됩니다. 방금 추가 한 업데이트 된 코드를 사용해야합니다.이 코드는 최신 브라우저에서 해당 사례를 다루는 것입니다.
jQuery를 사용하면됩니다.
$(window).blur(function(){
//your code here
});
$(window).focus(function(){
//your code
});
또는 적어도 그것은 나를 위해 일했습니다.
window
포커스가 느슨해 지지만 의도에 따라 필요하지 않을 수도 있습니다.
사용자가 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를 모방합니다. 동일한 방식으로 작동하지만 오 탐지율이 작습니다. 멀티 브라우저 (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>
현재 오 탐지없이 작동하는 크로스 브라우저 솔루션이 없으므로 웹 사이트에서 주기적 활동을 비활성화하는 것에 대해 두 번 생각하는 것이 좋습니다.
GitHub에는 깔끔한 라이브러리가 있습니다 :
https://github.com/serkanyersen/ifvisible.js
예:
// If page is visible right now
if( ifvisible.now() ){
// Display pop-up
openPopUp();
}
내가 가지고있는 모든 브라우저에서 버전 1.0.1을 테스트했으며 다음과 함께 작동하는지 확인할 수 있습니다.
... 그리고 아마도 모든 최신 버전 일 것입니다.
다음과 완벽하게 작동하지 않습니다.
.now()
항상 true
나에게 반환 ).사용 : 페이지 가시성 API
document.addEventListener( 'visibilitychange' , function() {
if (document.hidden) {
console.log('bye');
} else {
console.log('well back');
}
}, false );
사용해도 되나요 ? http://caniuse.com/#feat=pagevisibility
내 앱에 대한 혜성 채팅을 만들고 다른 사용자로부터 메시지를 받으면 다음을 사용합니다.
if(new_message){
if(!document.hasFocus()){
audio.play();
document.title="Have new messages";
}
else{
audio.stop();
document.title="Application Name";
}
}
document.hasFocus()
가장 깨끗한 방법입니다. 가시성 API 또는 이벤트 기반을 사용하거나 다양한 수준의 사용자 활동 / 활동 부족을 찾는 다른 모든 방법은 지나치게 복잡 해져서 복잡한 사례와 허점으로 가득 차게됩니다. 간단한 간격으로 놓고 결과가 변경되면 맞춤 이벤트를 발생시킵니다. 예 : jsfiddle.net/59utucz6/1
커뮤니티 위키 답변을 사용하기 시작했지만 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');
});
이 버전을 청취 모든 다른 가시성 이벤트 및 화재 그들 중 하나가 변화를 야기하는 경우 콜백. focused
와 unfocused
핸들러는 다수의 API를 같은 가시성 변경을 잡을 경우 콜백이 여러 번 호출하지 않아야합니다.
document.hidden
및 이 모두 document.webkitHidden
있습니다. 포함하지 않는 else
에 if
건설 우리는이 콜백 호출 권리를 얻을 것?
정말 까다 롭습니다. 다음 요구 사항이 주어지면 해결책이없는 것 같습니다.
이것은 다음과 같은 이유로 발생합니다.
이러한 제한이 주어지면-페이지 가시성 API-창 흐림 / 포커스-document.activeElement를 결합한 솔루션을 구현할 수 있습니다.
그것은 할 수 있습니다 :
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
나는 여전히 충분한 브라우저로 이것을 테스트하지 않았습니다. 이것이 작동하지 않는 위치에 대한 자세한 정보를 찾으면 아래 의견에 알려주십시오.
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);
});
당신은 사용할 수 있습니다 :
(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);
})();
HTML 5에서는 다음을 사용할 수도 있습니다.
onpageshow
: 창이 보일 때 실행될 스크립트onpagehide
: 창이 숨겨 졌을 때 실행될 스크립트보다:
이것은 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);
}
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)에 대한 대체 기능도 제공됩니다
약간 더 복잡한 방법은 setInterval()
마우스 위치를 확인하고 마지막 확인과 비교하는 데 사용 하는 것 입니다. 마우스가 일정 시간 동안 움직이지 않으면 사용자가 유휴 상태 일 수 있습니다.
이 대신에, 사용자가 유휴 상태 인 경우 이야기의 추가 이점이 바로 윈도우가 활성화되지 않은 경우 검사합니다.
많은 사람들이 지적했듯이, 사용자가 마우스를 사용하지 않거나 비디오를 보거나 그와 비슷한 것을 사용하기 때문에 항상 사용자 또는 브라우저 창이 유휴 상태인지 여부를 확인하는 좋은 방법은 아닙니다. 유휴 상태를 확인하는 한 가지 가능한 방법을 제안하고 있습니다.
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()
, 범위에있는 컨트롤러의 범위에 범위 기능이 있습니다.
당신이 행동을 할 경우 에 전체 브라우저 흐림 : 나는 주석으로, 만약 제안 된 이벤트 화재의 브라우저 잃게 초점 없음. 내 생각은 이벤트가 발생하면 루프에서 카운트 업하고 카운터를 재설정하는 것입니다. 카운터가 제한에 도달하면 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에서 성공적으로 테스트 된 초안입니다.
requestAnimationFrame
API를, 또는 주파수가있는 현대적인 기능을 사용하여setTimeout
/setInterval
(예를 들어, 크롬에서 1 초) 윈도우가 보이지 않을 때 감소한다.