对于WebIM 对话或其它各种Comet应用场景,当收到新消息时,希望能够及时提醒用户。
但是用户可能将窗口切换到计算机上其它窗口上了,比如看其它网页、聊一下QQ、收发一下邮件等各种其它事情,此时web窗口就不在用户焦点上了,收到的新消息时很可能看不到。而javascript控制的web窗口并不能很好融入到OS级别的窗口系统中。比较普遍的一种做法就是让浏览器标题栏不断闪烁,应用程序的标题闪烁是很容易被注意到的,不管是浏览器和其它各种程序之间,还是浏览器多tab或windows之间。这算是最接近OS级别窗口的提示方式了。
实现的目标:
- 当对话窗口失去焦点(切换到其它程序或其它浏览器窗口),并且收到新消息时,标题栏闪烁。
- 没有失去焦点时不闪烁提示。焦点重新回到窗口时,标题栏恢复正常不再闪烁。
一、标题栏的闪烁
要实现标题栏闪烁的效果很简单,只要让 title 的内容来回变化就可以。
比如每500ms,
document.title=“【您有新的消息】”
下次
document.title=“【 】”
这样来回变化就实现了闪烁效果。
二、浏览器窗口焦点的判断
根据目标的要求,首先要知道当前窗口激活状态。
注册window.onblur和window.onfocus函数来记录焦点变化,但是IE上的行为有差异,不能直接用,而应该用document.onfocusin和document.onfocusout。
关于window或Dom元素的focus焦点这方面的行为,各浏览器行为有差异,尤其IE的行为有很多bug。
//当前浏览器窗口是否处于焦点
var isWindowFocus = true;
function focusin() { isWindowFocus=true;}
function focusout() { isWindowFocus=false;}
//注册焦点变化监听器
if ("onfocusin" in document){//for IE
document.onfocusin = focusin;
document.onfocusout = focusout;
} else {
window.onblur = focusout;
window.onfocus= focusin;
}
三、具体实现
使用方式:每当收到新消息时就调用 doFlashTitle 方法实现闪烁,调用者不做任何判断。
要求:
1.如果当前窗口失去焦点一直执行title闪烁,如果当前处于窗口焦点则什么也不做。
2.当窗口重新获得焦点时,停止闪烁(退出闪烁循环)。
3.多次调用,闪烁循环本身只应执行一次。也就是说闪烁函数只同时运行一个,否则多个同样的调用一起执行的话会导致标题闪动异常(快),消耗资源。
//实现标题闪动效果
var flashStep=0; //交替变量
var flashTitleRun = false; //是否正在执行
var normalTitle = "正常显示的标题";
function flashTitle()
{
//仅窗口不在焦点时闪烁title,回到焦点时停止闪烁并将title恢复正常
if(isWindowFocus){//当前处于焦点
document.title=normalTitle;
flashTitleRun = false;
return;//退出循环
}
flashTitleRun = true;
flashStep++;
if (flashStep==3) {flashStep=1;}
if (flashStep==1) {document.title="【您有新的消息】";}
if (flashStep==2) {document.title="【 】";}
setTimeout("flashTitle()",500); //循环
}
//调用这个执行标题闪烁,而不是直接调用flashTitle,保证多次调用只会执行一次。
function doFlashTitle(){
if(!flashTitleRun)//没有执行时,才执行
flashTitle();
}
四、小结
title闪烁并不难,但跨浏览器的焦点判断的问题比较多,IE非常诡异。参考资料都是焦点判断方面的。
只能判断出窗口焦点是否激活,没有办法判断窗口对人是不是可见的。
在js中调用window.focus()方法,窗口到底会不会被激活是完全不可靠的。而在IE上执行此方法,不管窗口是否激活了,都会导致focus事件的触发,使得上述的判断方法认为已经获得焦点了,但其实没有。所以最好就不要再使用window或dom的focus方法,以免干扰判断。而非IE浏览器正常,只有窗口确实被激活了才触发focus事件。