Vue獲取掃碼槍輸入內容(可一定程度無視輸入法)
技術標籤:開發例項vuejsjavascript
Vue獲取掃碼槍輸入內容(可一定程度無視輸入法)
背景
WMS專案需要使用掃碼槍,但當我輸入法為中文輸入法時,掃碼槍輸入會出現中文或者缺字母少數字的情況,嘗試了不少方法,最終於找到了一種比較合適的解決辦法。
環境
名稱 | 內容 |
---|---|
語言 | Vue、ElementUI、Js |
掃碼槍 | 型號OBM-3802 |
前提
經過不停的掃碼和觀察,發現了一點掃碼槍的規律
- 掃碼槍掃描之後模擬了keyboardEvent鍵盤輸入(
廢話 - 掃碼槍掃描到大寫字母時,在傳送key為該字母的keyboardEvent事件後,還會附帶一個key為shift的keyboardEvent事件(這個事件在keydown裡面監聽不到),但是輸入小寫字母時不會附帶這個事件
- 掃碼槍模擬的事件很快,單個事件基本低於20~30毫秒,有的只要幾毫秒
- 當中文輸入法開啟後,在字母的keyboardEvent事件前都會帶一個key為Process的keyboardEvent事件(這個事件在keydown裡面是監聽不到)(這很重要)
方案
基於上述前提,我在此有兩種比較好的解決方案
一、隱藏密碼框法
眾所周知,密碼框是無視輸入法的,管你輸的什麼,只要不是特殊的按鍵,一律小黑點
程式碼
<template>
<div>
<el-form>
<el-form-item label="輸入條碼">
<el-input v-model="barcode" type="password" ref="barcode"></el-input>
<el-input v-model="barcode" type="text" placeholder="輸入條碼" readonly="readonly" @focus="handleFocus" style="top:-36px;"></el-input>
</el-form-item>
</el-form>
</div>
</template>
<script>
export default {
name: "Barcodescan",
data() {
return {
barcode: undefined
}
},
methods: {
handleFocus() {
this.$refs.barcode.select();
}
}
}
</script>
測試
好了,就這麼簡單,每次只要點選文字框,然後隨便你怎麼掃,都是對的,如果你需要重新掃,只需要再點一下文字框即可。然後就是無盡的調樣式之路。
優點
簡單
缺點
在你以為問題解決了的時候,作為一個成熟的程式設計師,你該想到,產品經理會問:我點了怎麼沒有選中樣式?我的滑鼠游標不在裡面,客戶會覺得自己不能掃碼,我的游標呢?為什麼這個框不能選中?客戶想複製怎麼辦?
結果
本人半路出家vue,雖然是個全棧,但是學藝不精,調了一上午樣式,一臉頭大的我,實在不知道游標怎麼模擬(這字母、數字、中文、符號長度都不一致太難搞了,我弄成長度一致了,小黑點又只能調字型大小,小黑點太大了,我的滑鼠游標也會跟著變大,凸(⊙▂⊙ )),網上也沒有找到大佬搞這個,然後果斷放棄了方案一。
二、輸入時間間隔法
根據掃碼槍輸的快,外加WMS倉庫人員輸條碼應該不會很快,再加個輸入法會有Process鍵盤事件這幾個特性。我有了個想法,要不不管輸入框的內容,他愛咋樣咋樣,我自己記keyboardEvent事件的輸入值好了。
程式碼
<template>
<div>
<!-- 阻止掃碼槍的Enter事件自動提交el-form的提交特性 -->
<el-form @submit.native.prevent>
<el-form-item label="輸入條碼">
<el-input v-model="barcode" type="text" placeholder="輸入條碼" @keyup.native="handleKeyUp"></el-input>
</el-form-item>
</el-form>
</div>
</template>
<script>
let barcodeVue = {
name: "Barcodescan",
data() {
return {
barcode: "",
realBarcode: "",
keyupLastTime: undefined,
};
},
methods: {
// 處理keyup事件
handleKeyUp(e) {
let gap = 0;
if (this.keyupLastTime) {
gap = new Date().getTime() - this.keyupLastTime;
if (gap > 50) {
gap = 0;
this.realBarcode = "";
}
}
this.keyupLastTime = new Date().getTime();
// 輸入法會觸發keyup事件,key為Process,跳過即可
if (e.key != "Process" && gap < 50) {
if (e.key.trim().length == 1) {
// 輸入單個字母或者數字
this.realBarcode += e.key;
} else if (e.key.trim() == "Enter") {
// 根據規則,判斷barcode型別,返回資料(自定義規則)
if (this.realBarcode) {
this.barcode = this.realBarcode;
this.realBarcode = "";
}else{
return;
}
}
}
}
}
};
export default { ...barcodeVue };
</script>
測試
優點
基本考慮了人正常的行為方式去開發的一個元件,當然體驗下來肯定是比方案一要好很多的,起碼focus之後框顏色會變,重要的是還有游標了。只要對方拿的是掃碼槍,不是掃碼機關槍,或者遇上人形掃碼槍,基本不會出什麼問題。
不足
儘管我們覺得體驗好了很多。但是作為一個成熟的程式設計師,應該會想到產品經理會說:你這個框還要點一下才能輸入啊,一點都不智慧!如果我有多個碼怎麼辦?就不能我開著頁面隨便掃,然後智慧的去判斷是什麼碼呢?
okokok,那我們在這個方案二的基礎上再改良一下。
結果
接著幹
三、頁面事件監聽+輸入事件間隔法
在方案二的基礎上,我決定從created執行盤古開天闢地之時就開始監聽事件,然後再根據自定義的業務規則去判斷掃碼的型別,最後根據門店門稱對比來確定本地還是其他門店單子。
程式碼
呼叫元件方
<template>
<div style="height:800px;width:800px;border:1px solid;padding:20px;margin:0 auto;margin-top:20px;">
<p style="text-align:center;">測試區域</p>
<barcodescan shopName="GZ1" @handle="handleBarcode"></barcodescan>
{{value}}
</div>
</template>
<script>
import Barcodescan from './components/Barcodescan'
export default {
name: 'Index',
components: {
Barcodescan
},
data() {
return {
value: undefined
}
},
methods: {
handleBarcode(barcodeMap) {
this.value = barcodeMap;
}
}
}
</script>
元件方
<template>
<div>
</div>
</template>
<script>
let barcodeVue = {
name: "Barcodescan",
props: {
shopName: {
type: String
}
},
data() {
return {
realBarcode: "",
keyupLastTime: undefined,
name: undefined,
regexRules: []
};
},
created() {
let that = this;
// 監聽頁面的keyup事件
document.onkeyup = function (e) {
that.handleKeyUp(e);
};
this.name = this.shopName;
this.initRegexRules();
},
methods: {
// 初始化條碼規則(自定義)
initRegexRules() {
this.regexRules = [
{
regex: "/^IN(\\w|\\d)+$/",
value: "putInStorageNumber"
},
{
regex: "/^CH(\\w|\\d)+$/",
value: "checkNumber"
},
{
regex: "/^AL(\\w|\\d)+$/",
value: "allocateNumber"
},
{
regex: "/^\\d{12}$/",
value: "orderNumber"
},
{
regex: "/^SR(\\w|\\d)+$/",
value: "transferNumber"
},
{
regex: "/^\\d{12}-\\d{3}$/",
value: "sendNo"
},
{
regex: "/^PL\\d{10}$/",
value: "wavePickingNumber"
},
{
regex: "/^PL\\d{10}-\\d{3}$/",
value: "wavePickingGroupNumber"
},
{
regex: "/^(\\w|\\d)*-[\\w|\\d]*-\\d*-[A-Z]-\\d*/",
value: "location"
}
]
},
// 處理keyup事件
handleKeyUp(e) {
let gap = 0;
if (this.keyupLastTime) {
gap = new Date().getTime() - this.keyupLastTime;
if (gap > 50) {
gap = 0;
this.realBarcode = "";
}
}
this.keyupLastTime = new Date().getTime();
// 輸入法會觸發keyup事件,key為Process,跳過即可
if (e.key != "Process" && gap < 50) {
if (e.key.trim().length == 1) {
// 輸入單個字母或者數字
this.realBarcode += e.key;
} else if (e.key.trim() == "Enter") {
// 根據規則,判斷barcode型別,返回資料(自定義規則)
if (this.realBarcode) {
let data = {
type: this.barcodeRule(this.realBarcode),
code: this.realBarcode,
isLocal: this.isLocal(this.realBarcode)
};
this.$emit('handle',data);
this.realBarcode = "";
}
}
}
},
// 判斷條碼型別,如果沒找到,則返回型別為barCode
barcodeRule(barcode) {
let value;
this.regexRules.some((item,index)=>{
let regex = eval(item.regex);
if(regex.test(barcode)){
value = item.value;
return true;
}
})
return value?value:"barCode";
},
// 根據條碼是否包含門店名,判斷是否本地條碼
isLocal(barcode) {
return this.name?barcode.indexOf(this.name)!=-1:undefined;
}
},
};
export default { ...barcodeVue };
</script>
測試
我在呼叫時設定的shopName為GZ1,表示本地門店名為GZ1
優點
頁面只需要設定@handle的方法,即可對掃描的內容去賦值、渲染,或者做什麼奇怪的操作都可以,最關鍵的是頁面只需要加一個標籤就行。隨便掃,隨便用。
不足
作為一個成熟的產品經理,差不多得了。
結果
就這樣吧