对于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.οnfοcus= 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事件