轉載於:https://segmentfault.com/a/1190000003942014
事件觸發時間
focus
:當focusable元素獲得焦點時,不支持冒泡;focusin
:和focus
一樣,只是此事件支持冒泡;blur
:當focusable元素失去焦點時,不支持冒泡;focusout
:和blur
一樣,只是此事件支持冒泡;
以前一直以為所有事件都是支持冒泡的,都是可以cancel的,查閱了[MDN上相關資料](https://developer.mozilla.org/en-US/docs/Web/Events)后,才發現有些事件支持冒泡,有些事件並不支持冒泡;有些事件有默認行為(這類事件可以cancel),有些事件壓根兒就沒有默認行為(這類事件就不能 cancel )。從 MDN 上可以清楚的看到 focus
和blur
這2種事件不支持冒泡,支持冒泡的事件是focusin
和focusout
。
事件觸發順序
對於同時支持這4個事件的瀏覽器,事件執行順序為focusin > focus > focusout > blur,代碼示例如下:
html代碼
<div class="parent"> <input type="text" /> </div> <div class="log"></div>
javascript代碼
function log(str){ $('.log').append($('<div/>').text(str)); } $('.parent') .focusin(function(){log('div focusin');}) .focusout(function(){log('div focusout');}) .focus(function(){log('div focus');}) .blur(function(){log('div blur');}); $('input') .focusin(function(){log('input focusin');}) .focusout(function(){log('input focusout');}) .focus(function(){log('input focus');}) .blur(function(){log('input blur');});
執行結果
從執行結果可以看到4個事件的執行順序,同時也可以看到 focus
/blur
是不支持冒泡的,所以.parent 元素綁定的focus
和blur
事件回調並沒有觸發。
focusin 與 focusout的瀏覽器支持
幾乎所有的瀏覽器都支持focus
和blur
事件,但對於focusin
和focusout
就不是這樣理想了。Firefox中不支持focusin
和focusout
事件;chrome和safari中只有通過addEventListener方式綁定事件才能正常使用,其他方式綁定都不行;
面對這樣的瀏覽器支持似乎很頭痛,慶幸的是jQuery對focusin
和focusout
做了兼容,使用$.focusin
和$.focusout
實現事件綁定,在所有瀏覽器中都支持;
focus
和blur
如何實現事件代理
事件代理簡單來說就是將子元素事件綁定在祖先元素上,之所以能夠這樣做,得益於標准事件模型的捕獲和冒泡。我們知道在標准事件模型中,一個事件的觸發會經歷三個階段:捕獲階段+目標階段+冒泡階段,有了捕獲和冒泡才能實現事件代理。由前面介紹可知,focus
和blur
不支持冒泡,但其支持捕獲,但 IE 中事件模型沒有捕獲只有冒泡,所以在非IE瀏覽器中可以通過在捕獲階段進行事件綁定實現事件代理。那么針對IE瀏覽器怎么實現呢?通過支持冒泡的是focusin
和focusout
實現就可以了。代碼示例如下:
html 代碼
<form name="form"> <input type="text" name="name" value="Your name"> <input type="text" name="surname" value="Your surname"> </form>
javascript 代碼
function addColor(){ this.style.background="red"; } var form = document.forms['form']; if (form.addEventListener) { // 非 IE 瀏覽器 form.addEventListener('focus', addColor, true); }else{ // IE form.onfocusin = addColor }
哪些元素是focusable的
在本文的第一小節提到了一個 focusable 元素的概念,我覺得有必要在這里解釋一下什么是focusable 元素。
默認情況下,只有部分html元素能獲得鼠標焦點如input
,很大一部分html元素是不能獲得鼠標焦點的如div
,這些能夠獲得鼠標焦點的元素就是focusable 元素。要想一個元素獲得焦點,可以通過三種方式:
-
鼠標點擊
-
tab 鍵
-
調用focus()方法
那么默認情況下,哪些元素是focusable 元素
-
window:當頁面窗口從隱藏變成前置可見時,focus 事件就會觸發
-
表單元素(form controllers):input/option/textarea/button
-
鏈接元素(links):a標簽、area標簽(必須要帶 href 屬性,包括 href 屬性為空)
-
設置了 tabindex 屬性(tabindex 值非-1)的元素
-
設置了contenteditable = "true"屬性的元素
tabindex
屬性
默認情況下就能 focusable 的元素太少,如果想讓一個 div
元素成為 focusable 的元素怎么做呢?很簡單,設置 tabindex 屬性即可!
tabindex 有2個作用:
-
使一個元素變成 focusable
只要在元素上設置了 tabindex 屬性,不管此屬性的值設為多少,此元素都將變成focusable元素。 -
定義多次按下 TAB 鍵時獲得焦點的元素順序
tabindex 屬性的值可以正數、0、負數,當多次按下TAB鍵,首先是tabindex為正數的元素獲得焦點,順序是:tabindex=1、tabindex=2、tabindex=3、tabindex=...,最后是tabindex=0的元素獲得焦點。注意:tabindex為負數的元素不能通過 TAB 鍵獲得焦點,只能通過鼠標點擊或者調用focus()方法才能獲得焦點。示例代碼如下:
<ul> <li tabindex="1" onfocus="showFocus(this)">One</li> <li tabindex="0" onfocus="showFocus(this)">Zero</li> <li tabindex="2" onfocus="showFocus(this)">Two</li> <li tabindex="-1" onfocus="showFocus(this)">Minus one</li> <li tabindex="-2" onfocus="showFocus(this)">Minus two</li> </ul>