H5移动端页面实现快递单号条形码二维码扫描
|
freeflydom
2025年11月4日 8:43
本文热度 234
|
公司项目要求实现H5页面可以扫描快递单条形码并回显快递单号,于是用html5-qrcode库实现条形码扫描功能。
关于 html5-qrcode
html5-qrcode 是一个基于 HTML5 和 JavaScript 的开源库,它利用浏览器的MediaDevices.getUserMedia() API 访问设备摄像头,实时扫描二维码(QR Code)和条形码(Barcode),无需安装插件或 App。
html5-qrcode 是一个轻量、高效、纯前端的 二维码/条形码扫描库,专为在网页(H5)中实现摄像头扫码功能而设计。
GitHub 仓库:https://github.com/mebjas/html5-qrcode
具体实现
实现效果:

项目基于vue3框架开发:
1.安装html5-qrcode:
npm install html5-qrcode
2.页面代码实现:
<template>
<div class="registration-container">
<h2>快递登记</h2>
<el-form label-position="top" :model="ruleForm" :rules="rules" ref="ruleFormRef">
<el-form-item label="真实退回快递单号" prop="expressNumber">
<el-input v-model="ruleForm.expressNumber" placeholder="请输入快递单号" clearable>
<template #suffix>
<SvgIcon @click="startScan" name="take-pictures" width="24" height="24" />
</template>
</el-input>
</el-form-item>
<el-form-item label="快递公司" prop="expressCompany">
<el-input v-model="ruleForm.expressCompany" placeholder="请输入快递公司" clearable />
</el-form-item>
</el-form>
<div class="footer">
<el-button class="submit-btn" type="primary" style="width: 100%" @click="submitForm">提交</el-button>
</div>
</div>
<div v-if="scanning" class="scanner-container">
<div id="qr-reader" ref="qrReaderRef"></div>
<p class="scan-hint">请将快递单条形码对准扫描框</p>
<el-button class="close-btn" @click="stopScan">关闭</el-button>
</div>
</template>
<script lang="ts" setup>
import { ref, onUnmounted, reactive } from 'vue'
import { Html5Qrcode } from 'html5-qrcode'
import { type FormInstance, type FormRules, ElMessage } from 'element-plus'
defineOptions({
name: 'after-sales-registration'
})
const ruleFormRef = ref<FormInstance>()
const ruleForm = reactive({
expressNumber: '',
expressCompany: ''
})
const rules = reactive<FormRules>({
expressNumber: [{ required: true, message: '请输入快递单号', trigger: 'blur' }],
expressCompany: [{ required: true, message: '请输入快递公司', trigger: 'blur' }]
})
const scanning = ref(false)
const qrReaderRef = ref(null)
let html5QrCode: Html5Qrcode | null = null
const startScan = (event: Event) => {
event.preventDefault()
event.stopPropagation()
if (scanning.value) return
scanning.value = true
if (document.activeElement instanceof HTMLElement) {
document.activeElement.blur()
}
setTimeout(() => {
try {
html5QrCode = new Html5Qrcode('qr-reader')
const config = {
fps: 10,
qrbox: { width: 300, height: 100 },
formats: [
'code_128',
'code_39',
'ean_13'
]
}
html5QrCode
.start(
{ facingMode: 'environment' },
config,
(decodedText) => {
ruleForm.expressNumber = decodedText
stopScan()
},
() => {}
)
.catch((err) => {
ElMessage.error('摄像头启动失败:' + (err.message || '未知错误'))
scanning.value = false
stopScan()
})
} catch (err) {
ElMessage.error(`扫码库初始化失败,请重试${err}`)
stopScan()
}
}, 300)
}
const stopScan = () => {
if (html5QrCode) {
html5QrCode
.stop()
.then(() => {
html5QrCode?.clear()
html5QrCode = null
scanning.value = false
})
.catch(() => {
scanning.value = false
})
} else {
scanning.value = false
}
}
const submitForm = () => {
ruleFormRef.value?.validate((valid) => {
if (valid) {
} else {
ElMessage.error('请填写完整信息')
}
})
}
onUnmounted(() => {
if (html5QrCode) {
html5QrCode.stop()
}
})
</script>
<style lang="scss" scoped>
.registration-container {
width: 100%;
height: 100%;
padding: 20px;
background: #f8f8fa;
box-sizing: border-box;
.footer {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
padding: 17px 0;
text-align: center;
box-shadow: 0px -4px 16px 0px rgba(60, 126, 254, 0.2);
box-sizing: border-box;
.submit-btn {
width: 50% !important;
background: #3c7efe;
border-radius: 555px;
}
}
}
input {
width: 100%;
padding: 14px;
margin: 10px 0;
border: 1px solid #ddd;
border-radius: 6px;
font-size: 16px;
box-sizing: border-box;
text-align: center;
background-color: #f9f9f9;
}
button {
width: 100%;
padding: 14px;
background-color: #d32f2f;
color: white;
border: none;
border-radius: 6px;
font-size: 16px;
cursor: pointer;
}
button:disabled {
background-color: #ef5350;
cursor: not-allowed;
}
button:hover:not(:disabled) {
background-color: #c62828;
}
.scanner-container {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: black;
z-index: 9999;
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-start;
padding-top: 40px;
}
#qr-reader {
width: 100%;
max-width: 500px;
border-radius: 14px;
overflow: hidden;
}
.scan-hint {
color: #4caf50;
margin-top: 14px;
font-size: 18px;
font-weight: bold;
}
.close-btn {
margin-top: 14px;
padding: 8px 16px;
background: #ff5252;
color: white;
border: none;
border-radius: 4px;
font-size: 14px;
}
</style>
其他
注意事项
- 必须 HTTPS:生产环境必须部署在 HTTPS 域名下。
- 用户授权:首次使用需用户允许摄像头权限。
- 性能优化:避免在低性能设备上长时间运行。
- 兼容性问题:在某些旧版浏览器可能不支持。
- 移动端体验:html5-qrcode 扫码体验一般,需要贴紧条形码。
其他方案对比
| 方案 | 技术栈 | 是否推荐 | 说明 |
|---|
1. html5-qrcode + 格式过滤 | 纯前端 JS | ✅✅✅ 强烈推荐 | 轻量、易用、支持条形码 |
2. ZXing JS(原生) | 纯前端 JS | ✅ 推荐 | 功能强大,但配置复杂 |
3. 原生 getUserMedia + QuaggaJS | 纯前端 JS | ⚠️ 可用但不推荐 | QuaggaJS 已停止维护 |
| 4. 调用微信 JS-SDK 扫码 | 微信内置 | ✅ 限微信环境 | 依赖微信 App |
| 5. 调用 App 原生能力(Hybrid) | WebView + Native | ✅ 高性能 | 需开发 App |
| 6. 拍照上传 + 后端识别 | 前端 + 后端 | ✅ 稳定兜底 | 适合弱网或兼容性差的设备 |
转自https://juejin.cn/post/7561706231033479209
该文章在 2025/11/4 8:43:22 编辑过