如何有效的捕获JavaScript焦点

2009年08月14日 由 Rock 回复 »

阅读本文可理解并解决以下问题:

  • 设置元素可获得焦点以监听键盘事件
  • 某个元素明明设置了聚焦却没效果
  • 聚焦时抛出异常的

1. 设置元素可获得焦点以监听键盘事件

元素聚焦最大好处就是可允许发送键盘事件,HTML很多元素默认就有可聚焦,如form表单元素,a锚链接等,但大部份默认是不能聚焦的。要使得元素能够聚焦,可以在HTML代码或JavaScript脚本中实现。

html:

  <div tabIndex="0" style="height:100px;width:100px; background:red;"></div>

JavaScript:
oDiv.tabIndex = 0;

其中tabIndex是TAB键的导航顺序,可有正,负或零。

当元素获得焦点时会有边框指示,如果想不显示这个边框,可以

html:

<div tabIndex="0"  hidefocus="on" ></div>

JavaScript:
oDiv.hideFocus = ‘on’;

2. 元素明明设置了聚焦却没效果

有时用JavaScript设置了元素聚焦,但最后焦点却不落在该元素上,百思不得其解。

问题在于如果在可焦点元素的事件处理函数中聚焦其它元素,就有可能聚不了焦点,因为如果该事件是个可获得焦点的事件,如mouse, keydow(keypress)等等,在这些事件的处理函数内直接聚焦其它元素是失败的。

oDiv.onmousedown = function(){
   document.getElementById('ipt').focus();
};

参考浏览器内核处理流程图:

当浏览器第一次Reflow回流后,焦点停在另一个元素上,但回流返回后,事件处理后默认的操作将继续执行,那就是聚焦到事件源,也就是mousedown的元素,这时引发第二次回流,当回流后焦点聚在该元素上.所以在事件处理函数中的聚焦变得无效.

有没解决方法? 答案是肯定的. 由图可知,只要把聚焦放到第二个Reflow回流之后执行即可.这个可利用setTimeout方法作延迟先放进队列等后再执行.因为由于JavaScript引擎单线程特性,图上整个过程都是连着执行的,该过程中JS引擎一直没有空闲过,当上面所有操作都完成后并后,定时回调才有机会被执行.所以可以:

oDiv.onmousedown = function(){
  setTimeout(function(){
      document.getElementById('ipt').focus();
   }, 0);
};

由上可知,最后那个毫秒数即使设为0也没关系.

3. 聚焦时抛出异常的
在IE中,当元素不可见时如果聚焦的话,会抛出一个异常,因为在很多应用中我们往往不再对元素是否不可见作测试就聚焦了,因为即使这样也没什么问题(谁说不可见元素就不可以聚焦的?)..所以,在IE下可用try{}catch(){}来忽略这个异常.

   try{
     element.focus();
   }catch(e){}

到此,与JavaScript焦点捕获相关的问题讨论就完成了.点击运行示例.

声明: 转载请注明转自 背光脚本 - www.bgscript.com

6 评论

  1. 路过…那个两次reflow让俺恍然大悟…非常感谢

  2. cc 说:

    这样理解不太对
    可以参考这个
    http://hax.javaeye.com/blog/191555

  3. Rock 说:

    我还是坚持我的观点,这是处理顺序问题。
    我不想具体去考查IE是否有foucus这bug,
    你可以在非IE浏览器下点击我里面的例子运行一次试试,这用IE BUG观点解释不了。

  4. cc 说:

    那里的意思是说
    html的focus跟window的focus产生的不同步的问题
    你可以测试

    document.getElementById(”t”).onmousedown = function(){
    document.getElementById(’d').focus();
    };

    在ie点第三个表单
    window的focus会在第三个表单上面
    这是正确的(跟你的理论是一致的)
    但我说的问题是你按一下tab,会focus到第二个上
    说明之前html的focus是在第一个上
    这里产生了不同步,我说的不太对就是说没有考虑这个bug,并不是说你的理论有错

  5. cc 说:


    被和谐了

  6. Rock 说:

    嗯,我明白你的意思了,不知这是否算是IE BUG,因为通过js调用focus聚焦本身并不是由用户行为触发的,所以也不一定要切换tab顺序,这样一来IE这做法也有一定理由呵,希望出发点是这样^-^

回复