1.扫描枪使用原理浅析。
扫描枪的使用原理其实很简单:就是把光信号转换成电信号,再将电信号通过模拟数字转换器转化为数字信号传输到计算机中处理。其实可以简单理解为:二维码/条形码 转换成 字符串。
2.扫描枪功能开发前准备。
正所谓“工欲善其事,必先利其器”,所以在准备开发此功能之前,我们得准备好两件事:
- 扫描枪与主机的接入(扫描枪按接口分类通常有四种:SCSI接口、EPP接口、USB接口、无线接口(蓝牙通讯),本文均以USB接口扫描枪在vue项目中开发为例。)
- 二维码/条形码(可用 草料官网 生成)。
3.扫描枪做了两件事。
- 识别二维码/条形码的内容并填入input文本框中。
- 自动执行键盘的回车事件。
4.核心代码与实例(单列)。
- 图解(单列):
- 核心代码(单列):
<el-table v-else :data="form.attrList" ref="newData" :height="tableHeight" key="pdlistbdk" border
tooltip-effect="dark" :header-cell-style="{ background: 'rgb(234,238,249)', color: '#333' }"
size="small">
<el-table-column label="序号" type="index" width="60" align="center"></el-table-column>
<el-table-column :label="item.titleName" :prop="'title' + i" align="center"
v-for="(item, i) in headData2" :key="i">
<template slot-scope="scope">
<el-input :placeholder="'请输入' + item.titleName" ref="rowIndex2"
v-model="scope.row[scope.column.property]" style="width: 100%" size="mini" clearable
@change="changeVal(scope)"
@keydown.enter.native="nextFocus2(i + 1, scope.$index, scope.row[scope.column.property])" />
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="100">
<template slot-scope="scope">
<span v-if="scope.$index !== 0" class="g-table-btn" style="font-size:14px"
@click="delNewData2(scope.row, scope.$index)"><i class="icon iconfont icontrash"
style="font-size:18px;color:#4574d0"></i>删除</span>
</template>
</el-table-column>
</el-table>
data() {
return {
loading: false,
tableHeight: '500',
form: {
attrList: [], //最终用于提交的表格数据
},
//动态表头数据(单列)
headData2: [
{
titleName: "设备ID",
id: 1
}
],
allNum2: 0, //总数(单列)
rowIndex2: 0, //行号(单列)
attrIndex2: 1, //输入框列数(单列)
delArr2: [], //(单列)
}
},
//新增行(单列)
addRow2() {
let query = {
index: this.rowIndex2
}
//不存在attrList 新增该属性并新增一行
if (!this.form.attrList) {
this.$set(this.form, "attrList", [query]);
} else {
this.form.attrList.push(query);
}
//页面加载完成后再获取焦点
this.$nextTick(() => {
this.$refs["rowIndex2"][this.allNum2].focus();
this.rowIndex2++
this.allNum2 = this.attrIndex2 * this.rowIndex2
})
},
//换行(单列),这里是因为实际项目会对每次扫码的内容做校验,所以加了接口。如果无需校验,直接执行res.code == 200内的代码即可。
nextFocus2(index, row, val) { //index为第几列(即为1);row为第几行(从0开始);val为当前文本框输入的值
if (!val || !val.trim()) {
this.$message({
message: '设备ID不能为空!',
type: 'warning',
showClose: true,
});
return false;
}
let data = new Object;
data.out_store_no = this.scheindexId;
data.device_id = val;
//校验
API.checkByScan(data)
.then(res => {
if (res.code == 200) {
if ((row + 1) * this.attrIndex2 < this.allNum2 && this.allNum2 != 0) {
let val = this.attrIndex2 * row + index
this.$refs["rowIndex2"][val].focus();
} else {
//最后一个输入框跳转新增一行
if (index % this.attrIndex2 == 0) {
this.addRow2();
if ((row + 1) % 240 == 0) { //是不是到了当前板的最后一行
this.autoPrint();
}
} else {
let val = this.attrIndex2 * (this.rowIndex2 - 1) + index
this.$nextTick(() => {
this.$refs["rowIndex2"][val].focus();
})
}
}
}
})
.catch(err => {
})
},
//删除行(单列)
delNewData2(row, index) {
this.delArr2.push(row.index);
this.form.attrList.splice(index, 1);
this.rowIndex2--;
this.allNum2 = this.attrIndex2 * this.rowIndex2;
let delResult2 = this.form.attrList.length % 240;
if (delResult2 == 0) {
this.boardNum = this.boardNum - 1;
}
},
//对每次扫码的数据进行处理,如无需额外处理,可去除。
changeVal(e) {
let curObj = e.row;
let curIndex = e.$index;
if (curObj.title0.includes('_')) {
this.form.attrList[curIndex].title0 = curObj.title0.split('_')[1]
} else {
this.form.attrList[curIndex].title0 = curObj.title0;
}
},
5.核心代码与实例(多列)。
- 图解(多列):
- 核心代码(多列):
<el-table v-if="detailData.whether_card == 1" :data="form.attrList" ref="newData" :height="tableHeight"
key="pdlistdk" border tooltip-effect="dark"
:header-cell-style="{ background: 'rgb(234,238,249)', color: '#333' }" size="small">
<el-table-column label="序号" type="index" width="60" align="center"></el-table-column>
<el-table-column :label="item.titleName" :prop="'title' + i" align="center"
v-for="(item, i) in headData" :key="i">
<template slot-scope="scope">
<el-input :placeholder="'请输入' + item.titleName" ref="rowIndex"
@change="changeVal(scope)"
v-model="scope.row[scope.column.property]" style="width: 100%" size="mini" clearable
@keydown.enter.native="nextFocus(i + 1, scope.$index, scope.row[scope.column.property])" />
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="100">
<template slot-scope="scope">
<span v-if="scope.$index !== 0" class="g-table-btn" style="font-size:14px"
@click="delNewData(scope.row, scope.$index)"><i class="icon iconfont icontrash"
style="font-size:18px;color:#4574d0"></i>删除</span>
</template>
</el-table-column>
</el-table>
data() {
return {
loading: false,
tableHeight: '500',
form: {
attrList: [], //最终用于提交的表格数据
},
//动态表头数据(多列)
headData: [
{
titleName: "设备ID",
id: 1
},
{
titleName: "ICCID",
id: 2
},
],
allNum: 0, //总数(多列)
rowIndex: 0, //行号(多列)
attrIndex: 2, //输入框列数(多列)
delArr: [], //(多列)
}
},
//对每次扫码的数据进行处理,如无需额外处理,可去除。
changeVal(e) {
let curObj = e.row;
let curIndex = e.$index;
if (curObj.title0.includes('_')) {
this.form.attrList[curIndex].title0 = curObj.title0.split('_')[1]
} else {
this.form.attrList[curIndex].title0 = curObj.title0;
}
},
//新增行(多列)
addRow() {
let query = {
index: this.rowIndex
}
//不存在attrList 新增该属性并新增一行
if (!this.form.attrList) {
this.$set(this.form, "attrList", [query]);
} else {
this.form.attrList.push(query);
}
//页面加载完成后再获取焦点
this.$nextTick(() => {
this.$refs["rowIndex"][this.allNum].focus();
this.rowIndex++
this.allNum = this.attrIndex * this.rowIndex
})
},
//换行(多列),这里是因为实际项目会对每次扫码的内容做校验,所以加了接口。如果无需校验,直接执行res.code == 200内的代码即可。
nextFocus(index, row, val) { //index为第几列(即为1和2);row为第几行(从0开始);val为当前文本框输入的值
if (!val || !val.trim()) {
this.$message({
message: index == 1 ? '设备ID不能为空!' : 'ICCID不能为空!',
type: 'warning',
showClose: true,
});
return false;
}
if (index == 1) { //不做校验
if ((row + 1) * this.attrIndex < this.allNum && this.allNum != 0) {
let val = this.attrIndex * row + index
this.$refs["rowIndex"][val].focus();
} else {
//最后一个输入框跳转新增一行
if (index % this.attrIndex == 0) {
this.addRow()
} else {
let val = this.attrIndex * (this.rowIndex - 1) + index
this.$nextTick(() => {
this.$refs["rowIndex"][val].focus();
})
}
}
} else { //校验
let data = new Object;
data.out_store_no = this.scheindexId;
data.device_id = this.form.attrList[row].title0;
data.iccid = this.form.attrList[row].title1;
API.checkByScan(data)
.then(res => {
if (res.code == 200) {
if ((row + 1) * this.attrIndex < this.allNum && this.allNum != 0) {
let val = this.attrIndex * row + index
this.$refs["rowIndex"][val].focus();
} else {
//最后一个输入框跳转新增一行
if (index % this.attrIndex == 0) {
this.addRow();
if ((row + 1) % 120 == 0) { //是不是到了当前板的最后一行
this.autoPrint();
}
} else {
let val = this.attrIndex * (this.rowIndex - 1) + index
this.$nextTick(() => {
this.$refs["rowIndex"][val].focus();
})
}
}
}
})
.catch(err => {
})
}
},
//删除行(多列)
delNewData(row, index) {
this.delArr.push(row.index);
this.form.attrList.splice(index, 1);
this.rowIndex--;
this.allNum = this.attrIndex * this.rowIndex;
let delResult = this.form.attrList.length % 120;
if (delResult == 0) {
this.boardNum = this.boardNum - 1;
}
},
6.总结。
如图为例,最终的扫码录入数据都是保存在了form.attrList中。以上就是扫描枪在vue实际项目中的基本使用。特别需要注意的是如果我们在自己项目中需要对每次扫码录入的数据做特殊处理,一定不能直接对v-model绑定的数据做更改,会抛异常,而是应该借住input的change事件对其处理。(v-model的双向数据绑定原理可查看我的另一篇文章--v-mode的双向数据绑定原理解析与日常案例使用分析)。