我有JavaScript,它周期性地执行活动。当用户没有在看站点时(例如,窗口或选项卡没有焦点),最好不要运行。
是否有一种方法可以使用JavaScript来做到这一点?
我的参考点:如果你正在使用的窗口不活跃,Gmail聊天就会播放声音。
我有JavaScript,它周期性地执行活动。当用户没有在看站点时(例如,窗口或选项卡没有焦点),最好不要运行。
是否有一种方法可以使用JavaScript来做到这一点?
我的参考点:如果你正在使用的窗口不活跃,Gmail聊天就会播放声音。
当前回答
对于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()是范围内任何控制器范围内的范围函数。
其他回答
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);
})();
我重读了@daniel-buckmaster的版本 我没有做多次尝试,但是,代码对我来说似乎更优雅…
// on-visibility-change.js v1.0.1, based on https://stackoverflow.com/questions/1060008/is-there-a-way-to-detect-if-a-browser-window-is-not-currently-active#38710376
function onVisibilityChange(callback) {
let d = document;
let visible = true;
let prefix;
if ('hidden' in d) {
prefix = 'h';
} else if ('webkitHidden' in d) {
prefix = 'webkitH';
} else if ('mozHidden' in d) {
prefix = 'mozH';
} else if ('msHidden' in d) {
prefix = 'msH';
} else if ('onfocusin' in d) { // ie 9 and lower
d.onfocusin = focused;
d.onfocusout = unfocused;
} else { // others
window.onpageshow = window.onfocus = focused;
window.onpagehide = window.onblur = unfocused;
};
if (prefix) {
visible = !d[prefix + 'idden'];
d.addEventListener(prefix.substring(0, prefix.length - 1) + 'visibilitychange', function() {
(d[prefix + 'idden'] ? unfocused : focused)();
});
};
function focused() {
if (!visible) {
callback(visible = true);
};
};
function unfocused() {
if (visible) {
callback(visible = false);
};
};
};
Chromium团队目前正在开发空闲检测API。从Chrome 88开始,它就可以作为原始试用版使用,这已经是该功能的第2个原始试用版了。早期的版本是从Chrome 84到Chrome 86。
它也可以通过一个标志来启用:
启用通过chrome://flags 要在本地使用空闲检测API进行实验,而不需要 源试用令牌,启用 #enable-experimental-web-platform-features标记 chrome: / /旗帜。
一个演示可以在这里找到:
https://idle-detection.glitch.me/
但必须指出的是,这个API是基于权限的(因为它应该是,否则这可能被滥用来监视用户的行为!)。
这真的很棘手。考虑到以下要求,似乎没有解决方案。
该页包括您无法控制的iframe 您希望跟踪可见性状态更改,而不管更改是由选项卡更改(ctrl+ TAB)或窗口更改(alt+ TAB)触发的。
这是因为:
页面可视性API可以可靠地告诉您一个选项卡更改(即使使用iframes),但它不能告诉您用户何时更改了窗口。 监听窗口模糊/聚焦事件可以检测alt+选项卡和ctrl+选项卡,只要iframe没有焦点。
考虑到这些限制,可以实现一个组合的解决方案 -页面可见性API -窗口模糊/聚焦 ——document.activeElement
能够:
1)当父页有焦点时按ctrl+tab: YES 2) iframe有焦点时按ctrl+tab: YES 3)当父页有焦点时,alt+tab: YES 4)当iframe有focus时,alt+tab: NO <——bummer
当iframe有焦点时,你的模糊/焦点事件根本不会被调用,页面可视性API也不会在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有一些控制,你可以使用postMessage API来做到这一点。
https://dl.dropboxusercontent.com/u/2683925/estante-components/visibility_test2.html
我还没有在足够多的浏览器上测试这个功能。 如果你能找到更多关于哪里不行的信息,请在下面的评论中告诉我。
对于没有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 < 10;iOS < 7)也可用