前情提要
筆者在工作環境中,有一個小週邊系統是給分行人員使用,其中有一段是需要透過Barcode Scanner
掃描其帳單中的條碼,作為Form
表單送出時的一個欄位,筆者看同事一開始的做法是在畫面上放一個Input
,其游標須Focus
在該Input
上,然後按下Barcode Scanner
去掃描條碼。
上述情境會延伸一些問題,使用者將游標移至其他表單元件或者系統上會有Toast
訊息,使用者可能會點擊其Toast
訊息關閉,上述零零總總情境後,若要掃描條碼,必須得將游標自動Focus
回條碼所屬的Input
上,極為困難,要寫很多code去做到;若沒有自動將游標Focus
回對應的Input
上,使用者會覺得困擾,每次掃描前都要移動滑鼠,將游標移回條碼所屬的Input
上,此篇內容就是要解決上述遇到的問題。
筆者這邊的開發環境如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| npm --version 6.14.11
node --version v10.24.0
ng --version _ _ ____ _ ___ / \ _ __ __ _ _ _| | __ _ _ __ / ___| | |_ _| / △ \ | '_ \ / _` | | | | |/ _` | '__| | | | | | | / ___ \| | | | (_| | |_| | | (_| | | | |___| |___ | | /_/ \_\_| |_|\__, |\__,_|_|\__,_|_| \____|_____|___| |___/
Angular CLI: 11.2.15 Node: 10.24.0 OS: win32 x64
Angular: 11.2.14 ... animations, common, compiler, compiler-cli, core, forms ... platform-browser, platform-browser-dynamic, router Ivy Workspace: Yes
Package Version --------------------------------------------------------- @angular-devkit/architect 0.1102.15 @angular-devkit/build-angular 0.1102.15 @angular-devkit/core 11.2.15 @angular-devkit/schematics 11.2.15 @angular/cli 11.2.15 @schematics/angular 11.2.15 @schematics/update 0.1102.15 rxjs 6.6.7 typescript 4.1.6
|
內容
筆者第一份工作就是做MES
相關軟體,其客戶環境都在工廠中,很常接觸到使用Barcode Scanner
的環境,其相對應的系統上的很多資料是從Barcode Scanner
讀取取得,那時就有一個觀念是監聽Keyboard
事件,因Barcode Scanner
的特性,分為兩種
- 一種是
Prefix, Suffix
特殊符號的方式判斷開始、結束,會有一個特殊的Prefix Code
,結尾都會帶Enter
鍵,就知道是從Barcode Scanner
輸入值r
- 一種是
Time-based
的方式判斷,畢竟人工輸入無法這麼快速,Barcode Scanner
掃描卻非常快速,利用這個特點,我們可以監聽全域的Keypress
事件,並且設定timeout
時間非常短暫,時間到將暫存的chars往外拋並清空,再回到初始狀態
第一種的有幾個現成包好的angular
套件可以使用,但筆者的情境可能無法適用
- 一是無法對於每個分行用甚麼
barcode scanner
做一些限制
- 二來不太可能一個新的
Barcode Scanner
就得幫它設定好Prefix
跟Suffix
筆者選擇第二種Time-based
的方式判斷,跟著筆者實作測試看看吧。
建立Angular專案
1 2 3
| ng new demo-code cd demo-code code .
|
撰寫Barcode監聽程式
建立好Angular專案,實作其程式,為demo,就直接寫在app.component.ts
中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| import { Component, HostListener, OnDestroy, OnInit } from '@angular/core'; import { FormBuilder, FormGroup } from '@angular/forms'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.scss'], }) export class AppComponent implements OnInit, OnDestroy { title = 'demo-barcode'; pressed = false; chars: any[] = []; frmDemo: FormGroup; constructor(private builder: FormBuilder) {} ngOnDestroy(): void {} ngOnInit(): void { this.frmDemo = this.builder.group({ barcode: [''], }); }
@HostListener('document:keypress', ['$event']) handleKeyboardEvent(e: KeyboardEvent) { if (e.which >= 48 && e.which <= 57) { this.chars.push(String.fromCharCode(e.which)); } if (this.pressed == false) { setTimeout(() => { if (this.chars.length >= 10) { var barcode = this.chars.join(''); this.frmDemo.get('barcode').setValue(barcode); } this.chars = []; this.pressed = false; }, 500); } this.pressed = true; } }
|
1 2 3
| <pre> {{ frmDemo.value | json }} </pre>
|
實際執行
實作完程式,執行看看吧,要準備好Barcode Scanner及各式各樣的條碼
在瀏覽器中開啟其對應網址,http://localhost:4200
,實作程式畫面中印出Form Value
即可知道有無掃描監聽成功,實際效果如下
1 2 3
| { "barcode": "0116100001088" }
|
結論
使用Time-based
的特性,搭配全域Keypress
事件取得Barcode Scanner
掃描出來的值變得如此簡單,不用再為Focus
來Focus
去而煩惱,不過這個只是demo
版本,實際應用時,可能也要加一些防呆機制,若條碼有規則,在timeout function
中做一個實際的驗證,這篇就到這邊了,希望有幫助到各位。
參考