打造更貼心的連動欄位網頁

在網頁設計中輸入欄位連動是很常見的情境,例如有員工編號及員工姓名兩個欄位,當使用者在輸入員工編號後,系統需自動帶出員工姓名。一般最直覺做法是利用<input>的onchange或onblur事件,在使用者輸入完成後送出AJAX呼叫向伺服器查詢後設定姓名欄位。程式範例如下: (展示)

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>傳統OnChange觸發</title>
    <script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.9.1.js"></script>
    <script>
        $(function () {
            $("#txtEmpNo").change(function () {
                $.get(
                    "DataSrc.ashx",
                    { key: $(this).val() },
                    function (res) {
                        $("#txtEmpName").val(res);
                    });
            });
        });
    </script>
    <style>
        .fld {
            width: 80px;
        }
    </style>
</head>
<body>
員編: 
<input id="txtEmpNo" class="fld"/> 
<input id="txtEmpName" readonly class="fld" style="background: #CCC" />
<input type="button" value="查詢" />
</body>
</html>

預期的操作流程是: 使用者輸入員工編號,右方灰底唯讀欄位帶出員工姓名供確認員編無誤,接著再按下查詢。

但是因為帶出姓名的邏輯放在change事件,使用者輸入124後,必須按Tab或點選其他網頁元素才會觸發AJAX呼叫。不熟操作的使用者,可能會在輸入完124後停止動作,卻苦等不到姓名出現,摸索一段時間才學到"多按一下Tab"的撇步。

為了改善操作流暢度,我們試著將查詢姓名的邏輯由onchange事件移到onkeyup按鍵事件,如此使用者按完鍵,毋需按Tab或點選其他欄位,系統就會直接帶出姓名。這種設計,應用於編號長度固定的情境還算完美,因為在keyup事件中可以檢查已輸入的文字長度,等待編碼完整再送出查詢。但若有效資料長度不一,就會產生困擾。例如: 在我們的範例程式中,1代表Transparent、11代表Blue、114代表Purple,於是在輸入114的過程,左側的欄位會依序冒出Transparent、Blue及Purple(見下方動畫展示),這意味著程式觸發了無效查詢,也干擾了使用者操作。(展示)

開發世界高手如雲,便有人想出巧妙解法 -- 使用者在輸入過程一般會先有連續打字的階段,輸入完畢後則會出現停頓,因此程式便可依按鍵間隔偵測使用者是否已輸入完畢,待全部輸入完畢後再送出查詢。透過這個技巧,電腦瞬間通人性,不需要多按鍵,又知道等輸入完成再查詢,提供更好的使用者體驗。

要使用JavaScript實踐構想並不困難,只需要在每次keyup事件時,不要直接送出AJAX,而是以window.setTimeout預定一段時間再送出(例如: 1秒),而在設定setTimeout時要留下識別,以便下次keyup時,先以clearTimeout清除上次預約的AJAX動作,再設定新的預約AJAX動作。如此,若按鍵後未滿一秒又按鍵,前次的AJAX查詢就會被取消,直到打完字停頓超過一秒沒按任何鍵,AJAX查詢才會真的送出。這段邏輯寫起來就會像下面這樣:

       $(function () {
            var hnd;
            $("#txtEmpNo").keyup(
                function () {
                    //取消前一次預定的查詢
                    window.clearTimeout(hnd);
                    //延遲一秒後才查詢,若這一段內又輸入其他字元
                    //則此一預約執行會被上一行程式取消
                    var value = $(this).val();
                    hnd = window.setTimeout(function () {
                        $.get(
                            "DataSrc.ashx",
                            { key: value },
                            function (res) {
                                $("#txtEmpName").val(res);
                            });
                    }, 1000);
            });
        });

操作過程如以下動畫所示,不需要額外Tab或點選,在輸入完成後又能自動帶出姓名,此種設計是不是更善解人意呢? (展示)

為了解說原理,我們剛才用setTimeout、clearTimeout自己造了輪子。但實務上不用這麼麻煩,網路已有現成Plugin可以實現前述構想,它有個術語叫Debounce(借用自電子學術語,指在接收訊息時避免發生誤動作的濾波機制),簡單列出幾個jQuery Plugin:

以下是改用doTimeout Plugin後的寫法: (展示)

        $(function () {
            $("#txtEmpNo").keyup(
                function () {
                    $(this).doTimeout("findEmpName",
                        1000, function () {
                            $.get(
                                "DataSrc.ashx",
                                { key: $(this).val() },
                                function (res) {
                                    $("#txtEmpName").val(res);
                                });
                        });
            });
        });

學會這招,大家不妨檢視自己專案中採用onchange、onblur觸發AJAX連動欄位的場合,看看有無調整的需要,試著讓自己的網頁作品更貼心吧!

歡迎推文分享:
Published 30 March 2013 05:49 PM 由 Jeffrey
Filed under:
Views: 18,841



意見

# Ga said on 09 April, 2013 10:29 PM

這真的是個好東西耶,

以前都沒想到@@

# player said on 01 June, 2013 05:04 AM

我在jqGrid裡用了類似這種功能

可是好難寫

花了一天才實驗出來

formatter

unformatter

edittype='custom'

editoptions 的 custom_element 與 ustom_value

通通都用上了

# monkey said on 30 August, 2013 09:11 AM

想問大大個問題

"DataSrc.ashx"

這是 擷取哪個地方...看不太懂,不知道能請大大指導一下嗎??

看起來好像是擷取資料表內的資料??但是....為什麼會是這樣的名字不明白??

# Jeffrey said on 31 August, 2013 03:46 AM

to monkey, ASHX是ASP.NET裡Generic Handler(泛型處理常式)的副檔名,你可以想像成一個不包含HTML UI,呼叫後傳回Text或JSON的ASP.NET網頁(參考: www.dotblogs.com.tw/.../20648.aspx)。在本範例中,DataSrc.ashx的角色是一支網頁程式,接收Request["key"]傳入的員工編號,查詢資料來源傳回員工姓名,由於我們的焦點在於Client端處理,將其視為黑盒子即可。

# monkey said on 02 September, 2013 07:42 PM

回版主大大:那如果用以上的code我用 php 製作,更改成與您一樣的方式,當使用者輸入資料就可以帶出相關資料(去擷取資料庫),這樣他要換去  get 哪裡... 這裡有點不太明白,懇請大大指教,感謝

# Jeffrey said on 03 September, 2013 09:00 AM

to monkey, 抱歉,不會寫PHP無法直接給範例,大致的方向是寫一個DataSrc.php取代DataSrc.ashx,在PHP中用$_GET['key']取得傳入參數,查詢資料庫取得對應資料,再以print(...)將結果傳回。

# monkey said on 04 September, 2013 07:37 AM

感謝大大的解析 :)  小弟已經有些明白了

謝謝您不辭辛勞的回答我

你的看法呢?

(必要的) 
(必要的) 
(選擇性的)
(必要的) 
(提醒: 因快取機制,您的留言幾分鐘後才會顯示在網站,請耐心稍候)

5 + 3 =

搜尋

Go

<March 2013>
SunMonTueWedThuFriSat
242526272812
3456789
10111213141516
17181920212223
24252627282930
31123456
 
RSS
創用 CC 授權條款
【廣告】
twMVC

Tags 分類檢視
關於作者

一個醉心技術又酷愛分享的Coding魔人,十年的IT職場生涯,寫過系統、管過專案, 也帶過團隊,最後還是無怨無悔地選擇了技術鑽研這條路,近年來則以做一個"有為的中年人"自許。

文章典藏
其他功能

這個部落格


Syndication