Используйте функцию callback()
внутри успеха foo()
. Попробуйте таким образом. Это просто и легко понять. & nbsp;
var lat = "";
var lon = "";
function callback(data) {
lat = data.lat;
lon = data.lon;
}
function getLoc() {
var url = "http://ip-api.com/json"
$.getJSON(url, function(data) {
callback(data);
});
}
getLoc();
С момента написания этого ответа новая спецификация достигла рекомендации благодаря W3C. API видимости страницы (в MDN ) теперь позволяет нам более точно определять, когда страница скрыта для пользователя.
Текущая поддержка браузера:
Следующий код использует API, возвращаясь к менее надежному методу размытия / фокусировки в несовместимых браузерах.
(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
, за исключением iOS, который использует onpageshow
и onpagehide
.
Несколько более сложным способом было бы использовать setInterval()
для проверки положения мыши и сравнения с последней проверкой. Если мышь не переместилась за определенное количество времени, пользователь, вероятно, не работает.
У этого есть дополнительное преимущество, говоря, что пользователь простаивает, вместо просто проверяя, не активировано ли окно.
Как отмечалось многими людьми, это не всегда хороший способ проверить, является ли пользователь или окно браузера бездействующим, так как пользователь может даже не использовать мышь или просматривает видео или подобное. Я просто предлагаю один из возможных способов проверить простоя.
Если вы хотите воздействовать на размытие всего браузера: как я уже говорил, если браузер не работает, ни один из предложенных событий не загорается. Моя идея - подсчитать в цикле и сбросить счетчик, если огонь события. Если счетчик достигает предела, я делаю location.href на другую страницу. Это также срабатывает, если вы работаете с dev-инструментами.
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.
Это адаптация ответа от Энди Е.
Это выполнит задачу, например. обновляйте страницу каждые 30 секунд, но только если страница видна и сфокусирована.
Если видимость не может быть обнаружена, будет использоваться только фокус.
Если пользователь фокусируется страницы, затем он немедленно обновится
Страница не будет обновляться снова до 30 секунд после любого вызова ajax
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, потому что тогда все, что вам нужно сделать, это следующее:
$(window).blur(function(){
//your code here
});
$(window).focus(function(){
//your code
});
Или, по крайней мере, это сработало для меня.
Я начал использовать ответ wiki сообщества, но понял, что он не обнаружил события alt-tab в Chrome. Это связано с тем, что он использует первый доступный источник событий, и в этом случае это API видимости страницы, который в Chrome, похоже, не отслеживает alt-tabbing.
Я решил немного изменить скрипт для отслеживания из всех возможных событий для изменения фокуса страницы. Вот функция, которую вы можете добавить:
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');
});
это работает для меня на chrome 67, firefox 67,
if(!document.hasFocus()) {
// do stuff
}
Я создаю чат Comet для своего приложения, и когда я получаю сообщение от другого пользователя, я использую:
if(new_message){
if(!document.hasFocus()){
audio.play();
document.title="Have new messages";
}
else{
audio.stop();
document.title="Application Name";
}
}
Просто хотел добавить: вопрос нечетко написан. «Когда пользователь не смотрит на сайт (т. Е. Окно или вкладка не имеют фокуса) ...»
Я могу посмотреть сайт, если он не имеет фокуса. Большинство настольных систем могут показывать окна параллельно:)
Вот почему API видимости страницы, вероятно, правильный ответ, поскольку он предотвращает обновление сайта, когда «пользователь не может видеть обновления», который может быть очень отличается от «вкладка не имеет фокуса».
Существует три типичных метода, используемых для определения того, может ли пользователь видеть HTML-страницу, однако ни одна из них не работает отлично:
onblur
поднят), но пользователь все еще может его увидеть (так что его все еще нужно обновлять). См. Также http://javascript.info/tutorial/focus Чтобы улучшить несовершенное поведение, описанное выше, я использую комбинацию из трех методов: W3C Visibility API, затем фокус / размытие и методы активности пользователя, чтобы уменьшить ложную положительную скорость. Это позволяет управлять следующими событиями:
Это как это работает: когда документ потеряет фокус, отслеживается активность пользователя (например, перемещение мыши) в документе, чтобы определить, видимо ли это окно. Вероятность видимости страницы обратно пропорциональна времени последнего действия пользователя на странице: если пользователь долгое время не выполняет никаких действий над документом, эта страница, скорее всего, не видна. Приведенный ниже код имитирует API видимости страниц W3C: он ведет себя одинаково, но имеет небольшую ложную положительную оценку. Преимущество состоит в том, чтобы быть мультибраузером (тестировался на Firefox 5, Firefox 10, MSIE 9, MSIE 7, Safari 5, Chrome 9).
<div id="x"></div> <script> /** Registers the handler to the event for the given object. @param obj the object which will raise the event @param evType the event type: click, keypress, mouseover, ... @param fn the event handler function @param isCapturing set the event mode (true = capturing event, false = bubbling event) @return true if the event handler has been attached correctly */ function addEvent(obj, evType, fn, isCapturing){ if (isCapturing==null) isCapturing=false; if (obj.addEventListener){ // Firefox obj.addEventListener(evType, fn, isCapturing); return true; } else if (obj.attachEvent){ // MSIE var r = obj.attachEvent('on'+evType, fn); return r; } else { return false; } } // register to the potential page visibility change addEvent(document, "potentialvisilitychange", function(event) { document.getElementById("x").innerHTML+="potentialVisilityChange: potentialHidden="+document.potentialHidden+", document.potentiallyHiddenSince="+document.potentiallyHiddenSince+" s<br>"; }); // register to the W3C Page Visibility API var hidden=null; var visibilityChange=null; if (typeof document.mozHidden !== "undefined") { hidden="mozHidden"; visibilityChange="mozvisibilitychange"; } else if (typeof document.msHidden !== "undefined") { hidden="msHidden"; visibilityChange="msvisibilitychange"; } else if (typeof document.webkitHidden!=="undefined") { hidden="webkitHidden"; visibilityChange="webkitvisibilitychange"; } else if (typeof document.hidden !=="hidden") { hidden="hidden"; visibilityChange="visibilitychange"; } if (hidden!=null && visibilityChange!=null) { addEvent(document, visibilityChange, function(event) { document.getElementById("x").innerHTML+=visibilityChange+": "+hidden+"="+document[hidden]+"<br>"; }); } var potentialPageVisibility = { pageVisibilityChangeThreshold:3*3600, // in seconds init:function() { function setAsNotHidden() { var dispatchEventRequired=document.potentialHidden; document.potentialHidden=false; document.potentiallyHiddenSince=0; if (dispatchEventRequired) dispatchPageVisibilityChangeEvent(); } function initPotentiallyHiddenDetection() { if (!hasFocusLocal) { // the window does not has the focus => check for user activity in the window lastActionDate=new Date(); if (timeoutHandler!=null) { clearTimeout(timeoutHandler); } timeoutHandler = setTimeout(checkPageVisibility, potentialPageVisibility.pageVisibilityChangeThreshold*1000+100); // +100 ms to avoid rounding issues under Firefox } } function dispatchPageVisibilityChangeEvent() { unifiedVisilityChangeEventDispatchAllowed=false; var evt = document.createEvent("Event"); evt.initEvent("potentialvisilitychange", true, true); document.dispatchEvent(evt); } function checkPageVisibility() { var potentialHiddenDuration=(hasFocusLocal || lastActionDate==null?0:Math.floor((new Date().getTime()-lastActionDate.getTime())/1000)); document.potentiallyHiddenSince=potentialHiddenDuration; if (potentialHiddenDuration>=potentialPageVisibility.pageVisibilityChangeThreshold && !document.potentialHidden) { // page visibility change threshold raiched => raise the even document.potentialHidden=true; dispatchPageVisibilityChangeEvent(); } } var lastActionDate=null; var hasFocusLocal=true; var hasMouseOver=true; document.potentialHidden=false; document.potentiallyHiddenSince=0; var timeoutHandler = null; addEvent(document, "pageshow", function(event) { document.getElementById("x").innerHTML+="pageshow/doc:<br>"; }); addEvent(document, "pagehide", function(event) { document.getElementById("x").innerHTML+="pagehide/doc:<br>"; }); addEvent(window, "pageshow", function(event) { document.getElementById("x").innerHTML+="pageshow/win:<br>"; // raised when the page first shows }); addEvent(window, "pagehide", function(event) { document.getElementById("x").innerHTML+="pagehide/win:<br>"; // not raised }); addEvent(document, "mousemove", function(event) { lastActionDate=new Date(); }); addEvent(document, "mouseover", function(event) { hasMouseOver=true; setAsNotHidden(); }); addEvent(document, "mouseout", function(event) { hasMouseOver=false; initPotentiallyHiddenDetection(); }); addEvent(window, "blur", function(event) { hasFocusLocal=false; initPotentiallyHiddenDetection(); }); addEvent(window, "focus", function(event) { hasFocusLocal=true; setAsNotHidden(); }); setAsNotHidden(); } } potentialPageVisibility.pageVisibilityChangeThreshold=4; // 4 seconds for testing potentialPageVisibility.init(); </script>
Поскольку в настоящее время нет рабочего кроссбраузерного решения без ложно положительный, вам следует подумать дважды о отключении периодической активности на вашем веб-сайте.
Использование: API видимости страницы
document.addEventListener( 'visibilitychange' , function() {
if (document.hidden) {
console.log('bye');
} else {
console.log('well back');
}
}, false );
Могу ли я использовать? http://caniuse.com/#feat=pagevisibility
u может использовать:
(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);
})();
Для решения без jQuery проверьте 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 & lt; 10; iOS & lt; 7)
В 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
для меня) В HTML 5 вы также можете использовать:
onpageshow
: сценарий запускается, когда окно становится видимым onpagehide
: скрипт запускается, когда окно скрыто См .:
Для 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()
- это функция области видимости в пределах области действия любого Контроллера.
Это действительно сложно. Кажется, что нет решения, учитывая следующие требования.
Это происходит из-за того, что:
Учитывая эти ограничения, можно реализовать решение, которое объединяет - страницу Visibility API - размытие / фокус окна - document.activeElement
Это может:
Когда фокус iframe имеет фокус, ваши события размытия / фокуса вообще не вызываются, а страница Visibility API выиграла ' t на вкладке alt +.
Я построил решение @ AndyE и реализовал это (почти хорошее) решение здесь: https://dl.dropboxusercontent.com/u/2683925/estante-components /visibility_test1.html (извините, у меня были некоторые проблемы с JSFiddle).
Это также доступно в Github: https://github.com/qmagico/estante-components
Это работает на хроме / хроме. Он работает на firefox, за исключением того, что он не загружает содержимое iframe (любая идея почему?)
В любом случае, чтобы решить последнюю проблему (4), единственный способ, которым вы можете это сделать, - прослушать для событий размытия / фокуса на iframe. Если у вас есть некоторый контроль над iframe, вы можете использовать API postMessage для этого.
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);
});