有3种典型方法用于确定用户是否可以看到HTML页面,但是它们都不能完美地工作:在W3C网页浏览权限API应该做到这一点(支持,因为:火狐10,MSIE 10,铬13)。但是,此API仅在完全覆盖浏览器选项卡时(例如,当用户从一个选项卡更改为另一个选项卡时)引发事件。当无法以100%的准确度确定可见性时,API不会引发事件(例如,Alt + Tab切换到另一个应用程序)。
使用基于焦点/模糊的方法会给您带来很多误报。例如,如果用户在浏览器窗口顶部显示较小的窗口,则浏览器窗口将失去焦点(onblur凸起),但用户仍然能够看到它(因此仍需要刷新)。另见http://javascript.info/tutorial/focus
依靠用户活动(鼠标移动,点击,键入键)也会给你带来很多误报。考虑与上述相同的情况,或观看视频的用户。
为了改善上述不完美行为,我结合使用了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上测试)。
/ **
将处理程序注册到给定对象的事件。
@param obj将引发事件的对象
@param evType事件类型:click,keypress,mouseover,...
@param fn事件处理函数
@param isCapturing设置事件模式(true =捕获事件,false =冒泡事件)
@return如果事件处理程序已正确附加,则为true
* /
function addEvent(obj,evType,fn,isCapturing){
if(isCapturing == null)isCapturing = false;
if(obj.addEventListener){
// Firefox
obj.addEventListener(evType,fn,isCapturing);
返回true;
} else if(obj.attachEvent){
// MSIE
var r = obj.attachEvent('on'+ evType,fn);
返回r;
} else {
返回false;
}
}
//注册潜在的页面可见性更改
addEvent(document,“potentialvisilitychange”,function(event){
document.getElementById(“x”)。innerHTML + =“potentialVisilityChange:potentialHidden =”+ document.potentialHidden +“,d
ocument.potentiallyHiddenSince =”+ document.potentiallyHiddenSince +“s
”;
});
//注册到W3C页面可见性API
var hidden = null;
var visibilityChange = null;
if(typeof document.mozHidden!==“undefined”){
隐藏= “mozHidden”;
visibilityChange = “mozvisibilitychange”;
} else if(typeof document.msHidden!==“undefined”){
隐藏= “msHidden”;
visibilityChange = “msvisibilitychange”;
} else if(typeof document.webkitHidden!==“undefined”){
隐藏= “webkitHidden”;
visibilityChange = “webkitvisibilitychange”;
} else if(typeof document.hidden!==“hidden”){
隐藏=“隐藏”;
visibilityChange = “visibilitychange”;
}
if(hidden!= null && visibilityChange!= null){
addEvent(document,visibilityChange,function(event){
document.getElementById(“x”)。innerHTML + = visibilityChange +“:”+ hidden +“=”+ document [hidden] +“
”;
});
}
var potentialPageVisibility = {
pageVisibilityChangeThreshold:3 * 3600,//以秒为单位
init:function(){
function setAsNotHidden(){
var dispatchEventRequired = document.potentialHidden;
document.potentialHidden = FALSE;
document.potentiallyHiddenSince = 0;
if(dispatchEventRequired)dispatchPageVisibilityChangeEvent();
}
function initPotentiallyHiddenDetection(){
if(!hasFocusLocal){
//窗口没有焦点=>检查窗口中的用户活动
lastActionDate = new Date();
if(timeoutHandler!= null){
clearTimeout(timeoutHandler);
}
timeoutHandler = setTimeout(checkPageVisibility,potentialPageVisibility.pageVisibilityChangeThreshold * 1000 + 100);
// +100毫秒以避免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){
//页面可见性更改阈值raiched =>提高均匀度
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:点击”。
});
addEvent(document,“pagehide”,function(event){
的document.getElementById( “X”)的innerHTML + = “pagehide / DOC:点击”。
});
addEvent(window,“pageshow”,function(event){
。的document.getElementById( “X”)的innerHTML + = “pageshow /赢:点击”; //在页面首次显示时引发
});
addEvent(window,“pagehide”,function(event){
。的document.getElementById( “X”)的innerHTML + = “pagehide /赢:点击”; //没有提出
});
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秒
potentialPageVisibility.init();
SCRIPT>
由于目前没有可用的跨浏览器解决方案而没有误报,因此您最好三思而后行,禁用网站上的定期活动。