簡單的東西不簡單,將 DOM 元素聚焦是個再簡單不過的功能了,在實務上也經常用到,但是我們最近在使用 FancyBox 利用 IFRAME 載入頁面時卻怎麼樣都無法讓游標自動停在特定的文字輸入框中,除此之外,我也將我這些年累積遇到無法 focus() 的問題做了一次總整理,一共有六個版本之多。
第一種:經典版
潛在的問題可以從官方提供的 Events/focus 文件看出一些端倪,但大部分的情況還是可以正常運作的,這也是讓 Web 開發人員匪夷所思的地方,就是有些地方可以用、有些地方不能用。
第二種:轉換成 DOM 去執行 focus() 函式
$('#Account')[0].focus();
使用 DOM 執行有很多風險,如果例外處理沒做好就很容易出現以下問題:
第三種:轉換成 DOM 去執行 focus() 函式,外加條件判斷確保執行無誤
if($('#Account').length > 0) { $('#Account')[0].focus(); }
你以為這樣就沒事了嗎?錯!因為當元素處於「隱藏」狀態時,是無法執行 DOM 物建的 focus() 函式的,硬要去執行就會出現以下錯誤:
第四種:轉換成 DOM 去執行 focus() 函式,外加條件判斷確保執行無誤,以及利用 setTimeout 修正笨 IE 的詭異錯誤。
if ($('#Account').length > 0) { setTimeout(function() { $('#Account')[0].focus(); }, 0); }
這問題會出現在 IE8 之前的 IE 瀏覽器上,通常發生在 DOM 元素先被隱藏,然後才被顯示出來 (這是常用的 hack 技法),雖然 DOM 元素已經在畫面上看的到,但 DOM 物件狀態還沒改變,導致執行 focus() 函式發生錯誤,這時就要用以上程式來解決。
第五種:轉換成 DOM 去執行 focus() 函式,外加條件判斷確保執行無誤,以及利用 setTimeout 修正笨 IE 的詭異錯誤,以及利用 try/catch 將最後可能潛在出現的問題給過濾掉。
if($('#Account').length>0){setTimeout(function(){try{$('#Account')[0].focus();}catch(e){}},0);}
以上應該算是我的終極解決版了,但不完美,所以我設計了第六個版本。
第六種:最終完美版
$('#Account').setfocus();
最後我將這些經驗濃縮成一個 jQuery 外掛 (Plugins),讓全網站有需要用到 focus() 功能的地方都可以利用 jQuery 自訂外掛函式達成目的。原始碼如下:
(function($)
{
jQuery.fn.setfocus = function()
{
return this.each(function()
{
var dom = this;
setTimeout(function()
{
try { dom.focus(); } catch (e) { }
}, 0);
});
};
})(jQuery);
對於剛從事 Web 甚或從事 Web 開發一段時間的人來說,真的很難想像能遭遇到多少大大小小、龜龜毛毛的的問題,但我卻還是不時會聽到有人說:「做網站很簡單阿,隨便一個大學生都可以做了」這樣的話,每次都是冷靜的想一想後決定:算了,這真的不是三言兩語講的清楚的,就讓誤解繼續下去吧~~
相關連結