焦点相关事件兼容性问题

概念:

 

除了常见的 focus,blur 事件,DOM Level 3 事件模块 还定义了 focusin ,focusout 以及 DOMFocusIn ,DOMFocusOut 四个事件。

 

规范:

 

blur :

在这个事件触发前,元素已经失去焦点,不冒泡,同步触发。target 指向当前失去焦点的元素。

 

DOMFocusIn :

在这个事件触发前,元素已经得到焦点,可冒泡,同步触发。target 指向当前得到焦点的元素。

 

DOMFocusOut :

 

在这个事件触发前,元素已经没有焦点,可冒泡,同步触发。target 指向当前失去焦点的元素。

 

focus:

在这个事件触发前,元素已经得到焦点,不冒泡,同步触发。target 指向当前得到焦点的元素。

 

focusin :

在当前元素获得焦点前以及相关元素失去焦点前触发,可冒泡,同步触发。target 指向当前将要获得焦点的元素,relatedTarget 指向失去焦点的元素

 

focusout :

在当前失去焦点前触发,可冒泡,同步触发。target 指向当前将要失去焦点的元素,relatedTarget 指向将要失去焦点的元素。

 

触发顺序:

 

假定有两个元素 1,2,先使得1 获得焦点再使得 2 获得焦点,那么事件的触发顺序以及触发源为

 

focusin -> 元素 1

元素 1 获得焦点

focus -> 元素 1

DOMFocusIn -> 元素 1

focusout -> 元素 1

focusin -> 元素 2

元素 1 失去焦点

blur -> 元素 1

DOMFocusOut ->元素 1

元素 2 获得焦点

focus -> 元素 2

DOMFocusIn -> 元素 2

 

兼容性测试:

 

测试代码:

Html代码 焦点相关事件兼容性问题 焦点相关事件兼容性问题焦点相关事件兼容性问题
  1. <div tabindex="-1" id='a1'>  
  2.     area 1   
  3. </div>  
  4.   
  5. <div tabindex="-1" id='a2'>  
  6.     area 2   
  7. </div>  
<div tabindex="-1" id='a1'>
    area 1
</div>

<div tabindex="-1" id='a2'>
    area 2
</div>

通过调用 focus()方法来进行焦点转移,(也可通过鼠标直接点击,但是就不能测试是否同步了)关于 div 的焦点可见这里

 

具体 demo @ google code

 

firefox 3.6.12

 

没有 focusin,focusout,DOMFocusIn,DOMFocusOut事件,focus,blur为同步触发

 

触发顺序为:

Js代码 焦点相关事件兼容性问题 焦点相关事件兼容性问题焦点相关事件兼容性问题
  1. a1 focus target:a1   
  2. a1 focus relatedTarget:   
  3. keydown : 49   
  4. a1 blur target:a1   
  5. a1 blur relatedTarget:   
  6. a2 focus target:a2   
  7. a2 focus relatedTarget:   
  8. keydown : 50  
a1 focus target:a1
a1 focus relatedTarget:
keydown : 49
a1 blur target:a1
a1 blur relatedTarget:
a2 focus target:a2
a2 focus relatedTarget:
keydown : 50
 

chrome 9.0

 

全部事件都实现了,且都为同步触发,但是触发顺序和规范不一致,并且没有定义 relatedTarget 事件属性:

Js代码 焦点相关事件兼容性问题 焦点相关事件兼容性问题焦点相关事件兼容性问题
  1. a1 focus target:a1   
  2. a1 focus relatedTarget:   
  3. a1 focusin target:a1   
  4. a1 focusin relatedTarget:   
  5. a1 DOMFocusIn target:a1   
  6. a1 DOMFocusIn relatedTarget:   
  7. keydown : 49   
  8. a1 blur target:a1   
  9. a1 blur relatedTarget:   
  10. a1 focusout target:a1   
  11. a1 focusout relatedTarget:   
  12. a1 DOMFocusOut target:a1   
  13. a1 DOMFocusOut relatedTarget:   
  14. a2 focus target:a2   
  15. a2 focus relatedTarget:   
  16. a2 focusin target:a2   
  17. a2 focusin relatedTarget:   
  18. a2 DOMFocusIn target:a2   
  19. a2 DOMFocusIn relatedTarget:   
  20. keydown : 50  
a1 focus target:a1
a1 focus relatedTarget:
a1 focusin target:a1
a1 focusin relatedTarget:
a1 DOMFocusIn target:a1
a1 DOMFocusIn relatedTarget:
keydown : 49
a1 blur target:a1
a1 blur relatedTarget:
a1 focusout target:a1
a1 focusout relatedTarget:
a1 DOMFocusOut target:a1
a1 DOMFocusOut relatedTarget:
a2 focus target:a2
a2 focus relatedTarget:
a2 focusin target:a2
a2 focusin relatedTarget:
a2 DOMFocusIn target:a2
a2 DOMFocusIn relatedTarget:
keydown : 50
 

只是将 focusxx DOMFocusXx 作为对应 focus,blur 的后面事件触发,没有使用意义。

 

ie

 

ie 支持 focusin ,focusout,并且同步触发顺序和规范一致,但是没有 target 以及 relatedTarget 事件属性。

对于 focus 以及 blur 为异步触发,同样没有 target 以及 relatedTarget 事件属性。

不支持 DOMFocusIn,DOMFocusOut。

 

触发顺序:

Js代码 焦点相关事件兼容性问题 焦点相关事件兼容性问题焦点相关事件兼容性问题
  1. a1 focusin target:null  
  2. a1 focusin relatedTarget:   
  3. keydown : 49   
  4. a1 focus target:null  
  5. a1 focus relatedTarget:   
  6. a1 focusout target:null  
  7. a1 focusout relatedTarget:   
  8. a2 focusin target:null  
  9. a2 focusin relatedTarget:   
  10. keydown : 50   
  11. a1 blur target:null  
  12. a1 blur relatedTarget:   
  13. a2 focus target:null  
  14. a2 focus relatedTarget:  
 a1 focusin target:null
 a1 focusin relatedTarget:
 keydown : 49
 a1 focus target:null
 a1 focus relatedTarget:
 a1 focusout target:null
 a1 focusout relatedTarget:
 a2 focusin target:null
 a2 focusin relatedTarget:
 keydown : 50
 a1 blur target:null
 a1 blur relatedTarget:
 a2 focus target:null
 a2 focus relatedTarget:

updated : 2010-12-10

一点奇怪的问题:在 ie9 pp7 下,当点击按钮,聚焦页面iframe的body时,iframe body 的 focusin 事件也是异步的!

例如会出现序列

Java代码 焦点相关事件兼容性问题 焦点相关事件兼容性问题焦点相关事件兼容性问题
  1. before click   
  2. after click   
  3. body focusin   
  4. body focus  
before click
after click
body focusin
body focus

 

 而不是

Java代码 焦点相关事件兼容性问题 焦点相关事件兼容性问题焦点相关事件兼容性问题
  1. before click   
  2. body focusin   
  3. after click   
  4. body focus  
before click
body focusin
after click
body focus
 

模拟 focusin/out

 

这次反过来了,在 focus 或 blur 前有事件触发并且支持子元素冒泡确实非常有用,可是目前 firefox 与 chrome 都不支持或者 触发 顺序不对,另一方面由于标准浏览器支持捕获capture,而捕获阶段恰恰在冒泡阶段前,虽然 focus/blur 不会冒泡,但是捕获阶段还是存在的,那么

 

handler1

Js代码 焦点相关事件兼容性问题 焦点相关事件兼容性问题焦点相关事件兼容性问题
  1. element.addEventListener("focus",function(){   
  2. // handler 1   
  3. },true);  
element.addEventListener("focus",function(){
// handler 1
},true);

也就比 handler2

Js代码 焦点相关事件兼容性问题 焦点相关事件兼容性问题焦点相关事件兼容性问题
  1. element.addEventListener("focus",function(){   
  2. // handler 2   
  3. },false);  
element.addEventListener("focus",function(){
// handler 2
},false);
 

先触发了,也就相当于 ie 下的

Js代码 焦点相关事件兼容性问题 焦点相关事件兼容性问题焦点相关事件兼容性问题
  1. element.attachEvent("onfocusin",function(){   
  2. //handler1   
  3. });  
element.attachEvent("onfocusin",function(){
//handler1
});

并且由于捕获时子元素获得焦点也会通知父元素,那么也就达到了 ie 以及规范规定的冒泡效果,这也正是 kissy 事件模块 用来全平台兼容 focusin/out 的方法了。

 

应用:

通过监控 form 即可监控各个输入域,当失去焦点以及得到焦点时进行处理:

Html代码 焦点相关事件兼容性问题 焦点相关事件兼容性问题焦点相关事件兼容性问题
  1. <form id='f'>  
  2.     <input id='i'/>  
  3.     <input id='i2'/>  
  4. </form>  
  5.   
  6. <script>         
  7.     KISSY.use("node",function(S,Node){   
  8.            
  9.         Node.one("#f").on("focusin",function(ev){   
  10.             console.log("focusin : "+ev.target.attr("id"));   
  11.         });   
  12.         Node.one("#f").on("focusout",function(ev){   
  13.             console.log("focusout : "+ev.target.attr("id"));   
  14.         });   
  15.     });   
  16. </script>  
<form id='f'>
    <input id='i'/>
    <input id='i2'/>
</form>

<script>		
	KISSY.use("node",function(S,Node){
		
		Node.one("#f").on("focusin",function(ev){
			console.log("focusin : "+ev.target.attr("id"));
		});
		Node.one("#f").on("focusout",function(ev){
			console.log("focusout : "+ev.target.attr("id"));
		});
	});
</script>