http://www.aygfsteel.com/ebecket 返還網(wǎng)
          隨筆-140  評(píng)論-11  文章-131  trackbacks-0

          這個(gè)問(wèn)題我大概在一年多以前在某個(gè)用到VML的頁(yè)面中(當(dāng)時(shí)倒是記錄了VML的一個(gè)嚴(yán)重問(wèn)題)首次發(fā)現(xiàn)了這個(gè)Bug。經(jīng)過(guò)一番狗狗之后,也未發(fā)現(xiàn)有同樣的報(bào)告。后來(lái)我又逐漸在幾種其他非VML的情形下重現(xiàn)了這個(gè)奇異的Bug。經(jīng)過(guò)一番探究,我大致推斷出了這個(gè)bug的原因。不過(guò)我一直沒(méi)有公開(kāi)發(fā)布過(guò)這個(gè)有趣的問(wèn)題,只是跟少數(shù)同事提到過(guò)它。這個(gè)bug有個(gè)有趣的特點(diǎn),就是西方人通常不會(huì)碰到這個(gè)bug。

          最近,真懶同學(xué)(realazy)在《認(rèn)識(shí)延遲時(shí)間為 0 的 setTimeout》一文中舉例說(shuō)明setTimeout的用途。代碼大意如下:

          Javascript代碼 復(fù)制代碼
          1. $('myButton').onmousedown = function () {   
          2.   var input = document.createElement('input');   
          3.   input.type = 'text';   
          4.   $('myDiv').appendChild(input);   
          5.   input.focus();   
          6. }  


          在IE中,新創(chuàng)建的input沒(méi)有如預(yù)期的獲得焦點(diǎn)。

          如果把input.focus()放在一個(gè)setTimeout中延時(shí)執(zhí)行,則就可以獲得焦點(diǎn)。

          這個(gè)例子本身其實(shí)并不能證明realazy想要說(shuō)明的觀點(diǎn),因?yàn)樗恍⌒呐龅搅艘粋€(gè)IE的微妙bug。在留言中,Lunatic Sun倒是敏銳的判斷出這是IE的bug,只是這個(gè)bug的本質(zhì)不是那么容易認(rèn)識(shí)到,它其實(shí)并不是onmousedown本身的bug。

          實(shí)際上,這是IE的focus機(jī)制的bug。

          IE中的所有元素其實(shí)并不是被憑空繪制出來(lái)的,而是統(tǒng)統(tǒng)基于已有的Windows控件之上。除了典型的按鈕、下拉菜單等,普通的div其實(shí)也是一個(gè)textbox控件。

          所以IE的HTML focus等實(shí)際是被轉(zhuǎn)換為windows控件的focus,于是在IE中存在兩種不同層次的focus機(jī)制。理想上,HTML的focus應(yīng)該被同步轉(zhuǎn)換為windows控件的focus,然而IE可憐的代碼導(dǎo)致這種轉(zhuǎn)換存在許多bug。我們經(jīng)常遇到的焦點(diǎn)虛線框丟失的問(wèn)題其實(shí)就是一個(gè)例子。

          實(shí)際上,在上面的例子中,表面上input沒(méi)有得到焦點(diǎn),但是其實(shí)調(diào)用focus()之后,HTML focus確實(shí)已經(jīng)到了新生成的input中,這一點(diǎn)你可以通過(guò)document.activeElement來(lái)驗(yàn)證,你也可以按tab和shift-tab觀察焦點(diǎn)的切換來(lái)證明這一點(diǎn)。然而,由于mousedown事件默認(rèn)會(huì)獲得控件焦點(diǎn),所以windows控件focus就跑回了你的按鈕上面了。這里出現(xiàn)了windows focus機(jī)制和html focus機(jī)制的脫節(jié)。顯然IE在focus上的同步代碼實(shí)在是太脆弱了。

          事實(shí)上,IE對(duì)焦點(diǎn)的控制似乎本來(lái)就不和邏輯。所有的hasLayout元素都能獲得焦點(diǎn)!結(jié)果一個(gè)頁(yè)面上大部分區(qū)域在mousedown之后焦點(diǎn)就不知跑到哪個(gè)元素上了——這顯然不是我們想要的行為——合乎HTML規(guī)范邏輯的行為應(yīng)該是只有交互控件,如表單控件和A元素等,才能獲得焦點(diǎn)。這導(dǎo)致一個(gè)典型的用戶(hù)體驗(yàn)問(wèn)題:在一個(gè)限制高度的可卷動(dòng)區(qū)域中(例如一個(gè)長(zhǎng)表單),拖動(dòng)scrollbar,控件焦點(diǎn)就丟失——實(shí)際焦點(diǎn)跑到scrollbar所在的元素(例如form元素)上了。最嚴(yán)重的是,body元素一般總會(huì)有scrollbar!為了緩解這個(gè)問(wèn)題,微軟為body元素打了補(bǔ)丁,使得body上的scrollbar不會(huì)搶走焦點(diǎn)。然而IE這個(gè)patch打得實(shí)在是太爛了,在標(biāo)準(zhǔn)模式下,canvas從body變成了html元素,所以頁(yè)面scrollbar就到了html元素上,結(jié)果bug又回來(lái)了!

          撇開(kāi)搶焦點(diǎn)問(wèn)題,我們回到前面的話(huà)題。

          既然html focus還是在input元素上,那么當(dāng)時(shí)windows控件焦點(diǎn)到底跑哪里去了?實(shí)際上這個(gè)焦點(diǎn)跑到了mousedown所發(fā)生的對(duì)象上。比如如果是一個(gè)input按鈕,焦點(diǎn)就會(huì)在該input按鈕實(shí)際對(duì)應(yīng)的windows的Button控件上。不過(guò)button元素的實(shí)現(xiàn)和一般的input不同,所以button元素上的mousedown之后,windows控件焦點(diǎn)實(shí)際上會(huì)跑到button元素外層的那個(gè)元素所對(duì)應(yīng)的windows控件(通常是TextBox控件)中。

          如何證明這一點(diǎn)?我過(guò)去用過(guò)一個(gè)調(diào)試工具可以顯示出每個(gè)html控件實(shí)際的windows控件,也能查看實(shí)際的windows系統(tǒng)焦點(diǎn)。不過(guò)現(xiàn)在想不起來(lái)那個(gè)工具的名稱(chēng)了。搞笑的是,此處還會(huì)出現(xiàn)一個(gè)非常orz的癥狀——也就是本文標(biāo)題所稱(chēng)的“西方人通常發(fā)現(xiàn)不了的一個(gè)IE的bug”——可以證明這一點(diǎn)。

          focus問(wèn)題 + 西方人通常發(fā)現(xiàn)不了。各位是否已經(jīng)猜到了呢?大家不妨用realazy的那個(gè)頁(yè)面中的第一個(gè)按鈕來(lái)直接實(shí)驗(yàn)一把。

          我會(huì)在下篇blog中繼續(xù)聊這個(gè)話(huà)題

          posted on 2009-10-12 16:21 becket_zheng 閱讀(343) 評(píng)論(0)  編輯  收藏

          只有注冊(cè)用戶(hù)登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 赞皇县| 若尔盖县| 望城县| 沈丘县| 汨罗市| 汶上县| 沁源县| 楚雄市| 阜平县| 中江县| 于田县| 泰宁县| 博兴县| 都匀市| 维西| 新营市| 武威市| 清镇市| 江津市| 那坡县| 泗阳县| 搜索| 台南市| 贞丰县| 安丘市| 连南| 舒城县| 曲麻莱县| 黄冈市| 孟连| 永定县| 信宜市| 镇江市| 永城市| 民勤县| 三河市| 奉贤区| 夏津县| 开平市| 南宁市| 山阳县|