﻿# 利用 jQuery 將 DOM 元素聚焦 focus() 的六個版本

簡單的東西不簡單，將 DOM 元素聚焦是個再簡單不過的功能了，在實務上也經常用到，但是我們最近在使用 [FancyBox](http://fancybox.net/) 利用 IFRAME 載入頁面時卻怎麼樣都無法讓游標自動停在特定的文字輸入框中，除此之外，我也將我這些年累積遇到無法 focus() 的問題做了一次總整理，一共有六個版本之多。

**第一種：經典版** 

```
$('#Account').focus();
```

潛在的問題可以從官方提供的 [Events/focus](http://docs.jquery.com/Events/focus) 文件看出一些端倪，但大部分的情況還是可以正常運作的，這也是讓 Web 開發人員匪夷所思的地方，就是有些地方可以用、有些地方不能用。

![jQuery Events/focus: This causes all of the functions that have been bound to the focus event to be executed. Note that this does not execute the focus method of the underlying elements.](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/d4a0eae002a88c8b13c1-image.png "jQuery Events/focus: This causes all of the functions that have been bound to the focus event to be executed. Note that this does not execute the focus method of the underlying elements.")

**第二種：轉換成 DOM 去執行 focus() 函式**

```
$('#Account')[0].focus();
```

使用 DOM 執行有很多風險，如果例外處理沒做好就很容易出現以下問題：

![This webpage contains errors that might prevent it from displaying or working correctly. If you are not testing this webpage, click No.  Error: '0' is null or not an object](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/3533e5fa719e7dc11f69-image.png "This webpage contains errors that might prevent it from displaying or working correctly. If you are not testing this webpage, click No.  Error: '0' is null or not an object")

!['0' 是 null 或不是一個物件](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/3c8dd34451982065b030-image.png "'0' 是 null 或不是一個物件")

**第三種：轉換成 DOM 去執行 focus() 函式，外加條件判斷確保執行無誤**

```
if($('#Account').length > 0) { $('#Account')[0].focus(); }
```

你以為這樣就沒事了嗎？錯！因為當元素處於「隱藏」狀態時，是無法執行 DOM 物建的 focus() 函式的，硬要去執行就會出現以下錯誤：

![Error: Can't move focus to the control because it is invisible, not enabled, or of type that does not accept focus](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/b3c7a6cb4c8b60bbd73b-image.png "Error: Can't move focus to the control because it is invisible, not enabled, or of type that does not accept focus")

![控制項不可見、為啟動或無法接受焦點，因此無法將焦點移到控制項上。](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/0bff9633f844ce291e05-image.png "控制項不可見、為啟動或無法接受焦點，因此無法將焦點移到控制項上。")

**第四種：轉換成 DOM 去執行 focus() 函式，外加條件判斷確保執行無誤，以及利用 setTimeout 修正[笨 IE 的詭異錯誤](http://stackoverflow.com/questions/1474660/javascript-visibility-error-in-ie-when-setting-focus-on-an-input-element)。**

```
if ($('#Account').length > 0) { setTimeout(function() { $('#Account')[0].focus(); }, 0); }
```

這問題會出現在 IE8 之前的 IE 瀏覽器上，通常發生在 DOM 元素先被隱藏，然後才被顯示出來 (這是常用的 hack 技法)，雖然 DOM 元素已經在畫面上看的到，但 DOM 物件狀態還沒改變，導致執行 focus() 函式發生錯誤，這時就要用以上程式來解決。

**第五種：轉換成 DOM 去執行 focus() 函式，外加條件判斷確保執行無誤，以及利用 setTimeout 修正[笨 IE 的詭異錯誤](http://stackoverflow.com/questions/1474660/javascript-visibility-error-in-ie-when-setting-focus-on-an-input-element)，以及利用 try/catch 將最後可能潛在出現的問題給過濾掉。**

```
if($('#Account').length>0){setTimeout(function(){try{$('#Account')[0].focus();}catch(e){}},0);}
```

以上應該算是我的終極解決版了，但不完美，所以我設計了第六個版本。

**第六種：最終完美版**

```
$('#Account').setfocus();
```

最後我將這些經驗濃縮成一個 jQuery 外掛 (Plugins)，讓全網站有需要用到 focus() 功能的地方都可以利用 jQuery 自訂外掛函式達成目的。原始碼如下：

```javascript
(function($)
{
    jQuery.fn.setfocus = function()
    {
        return this.each(function()
        {
            var dom = this;
            setTimeout(function()
            {
                try { dom.focus(); } catch (e) { } 
            }, 0);
        });
    };
})(jQuery);
```

對於剛從事 Web 甚或從事 Web 開發一段時間的人來說，真的很難想像能遭遇到多少大大小小、龜龜毛毛的的問題，但我卻還是不時會聽到有人說：「做網站很簡單阿，隨便一個大學生都可以做了」這樣的話，每次都是冷靜的想一想後決定：算了，這真的不是三言兩語講的清楚的，就讓誤解繼續下去吧~~

**相關連結**

-   [Events/focus - jQuery JavaScript Library](http://docs.jquery.com/Events/focus)
-   [Javascript: Visibility error in IE when setting focus on an input element](http://stackoverflow.com/questions/1474660/javascript-visibility-error-in-ie-when-setting-focus-on-an-input-element)
-   [\[jQuery\] 自製 jQuery Plugin – Part 1](https://jaceju.net/build-your-own-jquery-plugin-1/)
-   [\[jQuery\] 自製 jQuery Plugin – Part 2](https://jaceju.net/build-your-own-jquery-plugin-2/)
-   [jQuery 邊做邊學系列影片](http://msdn.microsoft.com/zh-tw/dd310332.aspx#jQuery)
