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);
}
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();
});
18 回答
http://jsfiddle.net/ARTsinn/JTxQY/
你可以用:
在HTML 5中,您还可以使用:
onpageshow
:窗口变为可见时运行的脚本onpagehide
:隐藏窗口时要运行的脚本看到:
https://developer.mozilla.org/en-US/docs/Web/Events/pageshow
https://developer.mozilla.org/en-US/docs/Web/Events/pagehide
自从最初编写此答案以来,由于W3C,新规范已达到推荐状态 . Page Visibility API(在MDN上)现在允许我们更准确地检测何时向用户隐藏页面 .
目前的浏览器支持
Chrome 13
Internet Explorer 10
Firefox 10
Opera 12.10 [阅读笔记]
以下代码使用API,回退到不兼容的浏览器中不太可靠的模糊/焦点方法 .
onfocusin
和onfocusout
是required for IE 9 and lower,而所有其他人都使用onfocus
和onblur
,iOS除外,它使用onpageshow
和onpagehide
.我会使用jQuery,因为那样你所要做的就是:
或者至少它对我有用 .
有3种典型的方法用于确定用户是否可以看到HTML页面,但是它们都不能完美地工作:
W3C Page Visibility API应该这样做(支持自:Firefox 10,MSIE 10,Chrome 13) . 但是,此API仅在完全覆盖浏览器选项卡时(例如,当用户从一个选项卡更改为另一个选项卡时)引发事件 . 如果无法以100%的准确度确定可见性,则API不会引发事件(例如,Alt Tab切换到另一个应用程序) .
使用 focus/blur based methods 会给你带来很多误报 . 例如,如果用户在浏览器窗口顶部显示较小的窗口,则浏览器窗口将失去焦点(
onblur
已提升),但用户仍然可以看到它(因此仍需要刷新) . 另见http://javascript.info/tutorial/focusRelying on user activity (鼠标移动,点击,键入键入)也会给你带来很多误报 . 考虑与上述相同的情况,或观看视频的用户 .
为了改善上述不完美行为,我结合使用了3种方法:W3C Visibility API,然后是焦点/模糊和用户活动方法,以降低误报率 . 这允许管理以下事件:
将浏览器标签更改为另一个(由于W3C页面可见性API,100%准确度)
页面可能被另一个窗口隐藏,例如由于Alt Tab(概率=不是100%准确)
用户注意力可能不会集中在HTML页面上(概率=不是100%准确)
这是它的工作原理:当文档松开焦点时,监视文档上的用户活动(例如鼠标移动)以确定窗口是否可见 . 页面可见性概率与页面上最后一次用户活动的时间成反比:如果用户长时间未对文档进行任何活动,则该页面很可能不可见 . 下面的代码模仿W3C页面可见性API:它的行为方式相同,但误报率很低 . 它具有多浏览器的优势(在Firefox 5,Firefox 10,MSIE 9,MSIE 7,Safari 5,Chrome 9上测试) .
由于目前没有可用的跨浏览器解决方案而没有误报,因此您最好三思而后行,禁用网站上的定期活动 .
GitHub上有一个整洁的库:
https://github.com/serkanyersen/ifvisible.js
例:
我已经在我拥有的所有浏览器上测试了1.0.1版,并且可以确认它适用于:
IE9,IE10
FF 26.0
Chrome 34.0
......可能还有所有新版本 .
不完全适用于:
.now()
总是为我返回true
)我为我的应用程序创建了Comet Chat,当我收到来自其他用户的消息时,我使用:
Using : Page Visibility API
Can i use ? http://caniuse.com/#feat=pagevisibility
这真的很棘手 . 鉴于以下要求,似乎没有解决方案 .
该页面包含您无法控制的iframe
无论TAB更改(ctrl选项卡)或窗口更改(alt选项卡)触发更改,您都希望跟踪可见性状态更改
这是因为:
页面可见性API可以可靠地告诉您标签更改(即使使用iframe),但它无法告诉您用户何时更改窗口 .
只要iframe没有焦点,聆听窗口模糊/焦点事件就可以检测到alt选项卡和ctrl选项卡 .
鉴于这些限制,可以实现一个结合的解决方案 - 页面可见性API - 窗口模糊/焦点 - document.activeElement
这能够:
1)父页面具有焦点时的ctrl选项卡:YES
2)iframe具有焦点时的ctrl选项卡:是
3)父页面具有焦点时的alt选项卡:是
当iframe有焦点时
4)alt选项卡:NO < - bummer
当iframe有焦点,您的模糊/焦点事件根本不会被调用,并且页面Visibility 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
我还没有用足够的浏览器测试过这个 . 如果您可以找到有关这不起作用的更多信息,请在下面的评论中告诉我们 .
我开始使用社区维基回答,但意识到它没有检测到Chrome中的alt-tab事件 . 这是因为它使用了第一个可用的事件源,在这种情况下,它是页面可见性API,在Chrome中似乎不跟踪alt-tabbing .
我决定稍微修改脚本以跟踪页面焦点更改的所有可能事件 . 这是一个你可以参与的功能:
像这样用它:
稍微复杂一点的方法是使用
setInterval()
检查鼠标位置并与上次检查进行比较 . 如果鼠标未在设定的时间内移动,则用户可能处于空闲状态 .这具有告知用户是否空闲的附加优点,而不仅仅是检查窗口是否处于活动状态 .
正如许多人所指出的那样,这并不总是检查用户或浏览器窗口是否空闲的好方法,因为用户可能甚至没有使用鼠标或正在观看视频等 . 我只是建议一种可能的方法来检查闲置 .
这是Andy E.答案的改编 .
这将完成一项任务,例如每隔30秒刷新一次页面,但前提是该页面是可见的并且是焦点 .
如果无法检测到可见性,则仅使用焦点 .
如果用户关注页面,则会立即更新
任何ajax调用后30秒内页面不会再次更新
对于没有jQuery的解决方案,请查看Visibility.js,它提供有关三个页面状态的信息
以及setInterval的便利包装器
旧版浏览器(IE <10; iOS <7)的后备也可用
对于angular.js,这是一个指令(基于接受的答案),它将允许您的控制器对可见性的变化作出反应:
您可以像下面这样使用它:
<div react-on-window-focus="refresh()">
,其中refresh()
是范围内的范围内的范围函数 .这适用于chrome 67,firefox 67,
如果你想行动 on 整个 browser blur :正如我评论的那样,如果浏览器松散焦点,则没有任何建议事件触发 . 我的想法是在循环中计数并在事件触发时重置计数器 . 如果计数器达到限制,我会将location.href用于其他页面 . 如果您使用开发工具,这也会激发 .
这是在FF上成功测试的草案 .
只是想补充一下:问题不清楚 . “当用户没有看到该网站时(即窗口或标签没有焦点)......”
我可以在没有焦点的情况下查看网站 . 大多数桌面系统都能够并行显示窗口:)
这就是为什么页面可见性API可能是正确的答案,因为当“用户无法看到更新”时,它会阻止更新网站,这可能与“选项卡没有焦点”非常不同 .