Tutorial on the use of code scanning gun (scanning gun) code scanning in Vue

1. Analysis of the working principle of the scanning gun.

The principle of use of the scanner is actually very simple: it converts the optical signal into an electrical signal, and then converts the electrical signal into a digital signal through an analog-to-digital converter and transmits it to a computer for processing. In fact, it can be simply understood as:  convert  the QR code/barcode into a string .

2. Preparation before the development of the scanner function.

As the saying goes, "If a worker wants to do a good job, he must first sharpen his tools", so before we are ready to develop this function, we have to prepare two things:

  • Access between the scanner and the host (there are usually four types of scanners classified by interface: SCSI interface , EPP interface , USB interface , and wireless interface (Bluetooth communication) . This article takes the development of the USB interface scanner in the Vue project as an example.)
  • QR code/barcode (can be generated on Forage official website ).

3. The scanner gun does two things.

  • Identify the content of the QR code/barcode and fill it in the input text box.
  • Automatically execute the enter event of the keyboard.

4. Core code and examples (single column).

  • Plot (single column):

  • Core code (single column):
<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. Core code and examples (multiple columns).

  • Graphical (multiple columns):

  • Core code (multiple columns):
<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. Summary.

As shown in the figure, for example, the final scanned code input data is stored in form.attrList . The above is the basic use of the scanner in the actual Vue project. Special attention should be paid to the fact that if we need to do special processing on the data entered by each scanning code in our own project, we must not directly change the data bound to the v-model, an exception will be thrown, but we should borrow the change of the input event processing. (For the principle of v-model's two-way data binding, please refer to my other article -- analysis of v-mode's two-way data binding principle and analysis of daily case use ).

Guess you like

Origin blog.csdn.net/Yi2008yi/article/details/131271464