這個問題我大概在一年多以前在某個用到VML的頁面中(當時倒是記錄了VML的一個嚴重問題)首次發(fā)現了這個Bug。經過一番狗狗之后,也未發(fā)現有同樣的報告。后來我又逐漸在幾種其他非VML的情形下重現了這個奇異的Bug。經過一番探究,我大致推斷出了這個bug的原因。不過我一直沒有公開發(fā)布過這個有趣的問題,只是跟少數同事提到過它。這個bug有個有趣的特點,就是西方人通常不會碰到這個bug。
最近,真懶同學(realazy)在《認識延遲時間為 0 的 setTimeout》一文中舉例說明setTimeout的用途。代碼大意如下:
- $('myButton').onmousedown = function () {
- var input = document.createElement('input');
- input.type = 'text';
- $('myDiv').appendChild(input);
- input.focus();
- }
$('myButton').onmousedown = function () {
var input = document.createElement('input');
input.type = 'text';
$('myDiv').appendChild(input);
input.focus();
}
在IE中,新創(chuàng)建的input沒有如預期的獲得焦點。
如果把input.focus()放在一個setTimeout中延時執(zhí)行,則就可以獲得焦點。
這個例子本身其實并不能證明realazy想要說明的觀點,因為他不小心碰到了一個IE的微妙bug。在留言中,Lunatic Sun倒是敏銳的判斷出這是IE的bug,只是這個bug的本質不是那么容易認識到,它其實并不是onmousedown本身的bug。
實際上,這是IE的focus機制的bug。
IE中的所有元素其實并不是被憑空繪制出來的,而是統(tǒng)統(tǒng)基于已有的Windows控件之上。除了典型的按鈕、下拉菜單等,普通的div其實也是一個textbox控件。
所以IE的HTML focus等實際是被轉換為windows控件的focus,于是在IE中存在兩種不同層次的focus機制。理想上,HTML的focus應該被同步轉換為windows控件的focus,然而IE可憐的代碼導致這種轉換存在許多bug。我們經常遇到的焦點虛線框丟失的問題其實就是一個例子。
實際上,在上面的例子中,表面上input沒有得到焦點,但是其實調用focus()之后,HTML focus確實已經到了新生成的input中,這一點你可以通過document.activeElement來驗證,你也可以按tab和shift-tab觀察焦點的切換來證明這一點。然而,由于mousedown事件默認會獲得控件焦點,所以windows控件focus就跑回了你的按鈕上面了。這里出現了windows focus機制和html focus機制的脫節(jié)。顯然IE在focus上的同步代碼實在是太脆弱了。
事實上,IE對焦點的控制似乎本來就不和邏輯。所有的hasLayout元素都能獲得焦點!結果一個頁面上大部分區(qū)域在mousedown之后焦點就不知跑到哪個元素上了——這顯然不是我們想要的行為——合乎HTML規(guī)范邏輯的行為應該是只有交互控件,如表單控件和A元素等,才能獲得焦點。這導致一個典型的用戶體驗問題:在一個限制高度的可卷動區(qū)域中(例如一個長表單),拖動scrollbar,控件焦點就丟失——實際焦點跑到scrollbar所在的元素(例如form元素)上了。最嚴重的是,body元素一般總會有scrollbar!為了緩解這個問題,微軟為body元素打了補丁,使得body上的scrollbar不會搶走焦點。然而IE這個patch打得實在是太爛了,在標準模式下,canvas從body變成了html元素,所以頁面scrollbar就到了html元素上,結果bug又回來了!
撇開搶焦點問題,我們回到前面的話題。
既然html focus還是在input元素上,那么當時windows控件焦點到底跑哪里去了?實際上這個焦點跑到了mousedown所發(fā)生的對象上。比如如果是一個input按鈕,焦點就會在該input按鈕實際對應的windows的Button控件上。不過button元素的實現和一般的input不同,所以button元素上的mousedown之后,windows控件焦點實際上會跑到button元素外層的那個元素所對應的windows控件(通常是TextBox控件)中。
如何證明這一點?我過去用過一個調試工具可以顯示出每個html控件實際的windows控件,也能查看實際的windows系統(tǒng)焦點。不過現在想不起來那個工具的名稱了。搞笑的是,此處還會出現一個非常orz的癥狀——也就是本文標題所稱的“西方人通常發(fā)現不了的一個IE的bug”——可以證明這一點。
focus問題 + 西方人通常發(fā)現不了。各位是否已經猜到了呢?大家不妨用realazy的那個頁面中的第一個按鈕來直接實驗一把。
我會在下篇blog中繼續(xù)聊這個話題
posted on 2009-10-12 16:21
becket_zheng 閱讀(342)
評論(0) 編輯 收藏