最近更新: 2010-09-06

在 Web 介面中,塑造便利的條碼讀取操作體驗

在 Kiosk 、旅客導覽系統或門禁系統中,通常只連接有限的資料輸入設備。主要是提供觸控螢幕,允許使用者點選畫面選項,以便操作公開性的服務。進階者,則提供特制數字鍵盤、條碼讀取機、RFID讀取機等輸入設備,讓使用者輸入由數字構成的文字資料。

本文說明所用的案例,便是一個提供條碼讀取機的Web介面導覽系統,它會在畫面上顯示一個書籍感應畫面,提示顧客將書籍的背面的ISBN條碼放到條碼讀取處讀取,然後將它的 ISBN 送到後端查詢書籍資訊。

案例說明

在一般電腦系統的操作經驗中,我們在輸入資料前,要先用滑鼠點取文字輸入框,使得文字輸入框取得輸入焦點,然後我們才能透過鍵盤或條碼機輸入資料。而在這個案例中,我們希望提供更便利的使用者經驗。我們希望顧客不必用滑鼠或觸控螢幕點取輸入框,也不必先注意文字輸入框是否取得輸入焦點。顧客只需要把條碼放在讀取處,資料就會被讀取與送出查詢。我們要讓顧客看不到文字輸入框,又要時時保持輸入焦點,以便隨時接受來自條碼機的資料。

掩蔽控制項

我先說明一下標題用「掩蔽」這個詞的用意。HTML 對於控制項的隱藏行為有特殊定義,所以要讓顧客看不到文字輸入框,只能選擇讓控制項不起眼。也就是把控制項掩蔽在畫面環境之中,讓顧客不會注意到它。

根據 HTML 規範,CSS 屬性為 visibility:hiddendisplay:none 的控制項,不能取得輸入焦點,故不能接受來自輸入設備的資料。 欲隱藏文字輸入控制項,並接受來自輸入設備的資料,可行方式為設定 CSS 屬性之文字顏色與底色相同、無邊框、且寬度為1px (對某些瀏覽器而言(如 Google Chrome),控制項寬度為0時,視同不可見(display:none),無法輸入。故我們可用的最小寬度為1px) (color:white;background:white;border:0;width:1px;)。

資取讀取動作

一個不與 form 綁定的文字輸入控制項,可透過 onchange, onkeypressonblur 事件,捕抓 Enter 的動作。See also: HTML4.0 - Intrinsic events

  • onchange - The onchange event occurs when a control loses the input focus and its value has been modified since gaining focus.
    只有在內容改變過的情形下失去焦點時,才會觸發事件。 例如連續按Enter或連續讀取同一個資料條碼的情形,因為在連按Enter時,並沒有改變控制項,因此只會觸發一次事件。
  • onblur - The onblur event occurs when an element loses focus either by the pointing device or by tabbing navigation.
    任何將焦點移出文字輸入框的動作,都會觸發此事件。包括按下 Enter 、觸控點擊其他控制項、切換應用程式等等。 由於此事件涵蓋內容太廣,經常在非程序員預想狀況下觸發,非最佳選擇。
  • onkeypress - 鍵值依平台而有所差異,非最佳選擇。 Enter的鍵值通常是 13.
保持輸入焦點

當使用者經由觸控螢幕點擊畫面其他內容時,就會轉移輸入焦點。若不特別處理,則文字輸入框無法接受條碼機讀取的資料。要時時保持文字輸入框的輸入焦點,可以藉由 onblur 事件處理方法實現。只要文字輸入框失去焦點的事件發生了,就重新讓文字輸入框取得輸入焦點。但因為我們不能在 noblur 事件處理過程中指定輸入焦點,所以還要透過 setTimeout() 延時指定輸入焦點。

實作 OccultReader 與用例

OccultReader.js

我用 JavaScript 實作了一個 OccultReader ,它實現了上述三點:掩蔽控制項、資料讀取以及保持輸入焦點。透過它便可以將 Web 頁面上的一個文字輸入框掩蔽起來;當條碼機讀取到資料後,會調用我們指定的處理函數。

// Copyright (c) 2010 rock 遊手好閒的石頭成

// Licensed by GNU LGPL.

OccultReader = new (function() {
    var control = false;
    var onchange_handler = false;

    /**
     * id: id of element.
     * args:
     *  style
     *  onchange_handler = function(value)
     */
    this.setControl = function(id, args) {
        control = document.getElementById(id);

        if (args && args.onchange_handler)
            onchange_handler = args.onchange_handler;

        control.onchange = function() {
            if ( onchange_handler ) {
                onchange_handler(control.value);
            }
            else {
                alert("Input: " + control.value +
                    "\n using args.onchange_handler to set this handler.");
            }
            control.value = ""; //reset data

        }

        //keep focus.

        control.onblur = function() {
            setTimeout("document.getElementById('" +
                control.id + "').focus();", 100);
        }

        if (args && args.style) {
            for (var style in args.style) {
                control.style[style] = args.style[style];
            }
        }
        else {
            with (control.style) {
                color = background = "white";
                border = "0";
                width = "1px";
            }
        }

        control.value = "";
        control.focus();
    }
});

OccultReader 需要調用其方法 setControl() 啟用。第一個參數指定文字輸入控制項的 ID。第二個參數則是一個表,可以在這表中指定控制項的 styleonchange_handleronchange_handler 負責取得資料後的事件處理方法。

關於 OccultReader 所使用的 JavaScript 資料與方法封裝技巧,請參閱本人另兩篇著作: 掌握 JavaScript 的「封裝」特性, part 1 掌握 JavaScript 的「封裝」特性, part 2 ,在此不多加說明。
isbn_report.php

以下是我實作的 ISBN 查詢系統範例。

<?php
$isbn_list = array(
    '9787101070743' => array('春秋左傳注', '楊伯峻', 'Jan 01, 2009'),
    '9789570809909' => array('讀易三種', '屈萬里', 'Jun 01, 1983')
);

$isbn = isset($_POST['isbn']) ? $_POST['isbn'] : FALSE;
if (preg_match('/^\w+$/', $isbn) == 0)
    $isbn = FALSE;
?>

<script type="text/javascript" src="OccultReader.js"></script>
<script type="text/javascript">
function form_post(v) {
    document.getElementById("isbn").value = v;
    document.getElementById("form1").submit();
}

function body_loaded() {
    OccultReader.setControl("isbn_entry",
        { onchange_handler: form_post }
        );
}
</script>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

<body onload="body_loaded();">
<h1>
書籍查詢 (ISBN Read and Report)
</h1>

<?php if ($isbn): ?>
    <h2>書籍條碼: <?=$isbn?></h2>

    <?php if (!isset($isbn_list[$isbn])): ?>
        <p><em>無此書籍資訊。</em></p>
    <?php else: ?>
        <p>書名: <?=$isbn_list[$isbn][0];?></p>
        <p>作者: <?=$isbn_list[$isbn][1];?></p>
        <p>出版日期: <?=$isbn_list[$isbn][2];?></p>
    <?php endif; ?>

    <hr/>
<?php endif; ?>

<p>
請將書籍背面的條碼放到條碼讀取區中。
</p>
<p>等待中...</p>
<input id="isbn_entry" type="text" />

<form id="form1" action="isbn_report.php" method="post">
<input id="isbn" name="isbn" type="hidden" />
</form>
</body>

當頁面載入完成後,便調用 OccultReader.setControl() ,指示 isbn_entry 控制項負責資料讀取,指定 form_submit()onchange_handler。當取得資料後,便會調用 form_submit() ,送出查詢資料。

操作示例 - ISBN reader

控制項的掩蔽效果視瀏覽器而定,大部份瀏覽器只會看到游標閃爍,而不會看到輸入框。

決定使用者的軟體操作經驗(或稱「易用性」)的關鍵因素,通常不在軟體的功能強弱,而是在一些細微的連貫動作。 在本文的案例中,便是將設定輸入焦點、取得資料、送出查詢三個動作連貫起來,令使用者不須在螢幕上進行其他操作,就可完成查詢動作。透過這樣小小的改變,就能達成改善操作經驗的目的。這是易於運用在 Kiosk 、旅客導覽系統等操作介面的技巧。

樂多舊網址: http://blog.roodo.com/rocksaying/archives/13676325.html

樂多舊回應
dplayerd@hotmail.com(毛豆) (#comment-21213859)
Sat, 11 Sep 2010 15:05:53 +0800
如果使用CSS
input {
margin-left:-2000px
}

這樣可以嗎?
未留名 (#comment-21218731)
Mon, 13 Sep 2010 15:19:34 +0800
此案例不需要掩蔽所有的 input 控制項,只需要掩蔽一個。所以你應該用 ID selector ,如本例: input#isbn_entry {}.

另外,我實作的 OccultReader,可以透過參數 style 設定屬性。在 JavaScript 中, margin-left 對應的屬性名稱是 marginLeft 。

邊界用負值的顯示效果,視瀏覽器而定。我記得有些瀏覽器會跑出捲軸. 我試了 Firefox3.6 和 Chrome ,設定 margin-left 為負值,確實有更好的掩蔽效果。