H5移动端页面实现快递单号条形码/二维码扫描,亲测可行!!

公司项目要求实现H5页面可以扫描快递单条形码并回显快递单号,于是用html5-qrcode库实现条形码扫描功能。

关于 html5-qrcode

html5-qrcode 是一个基于 HTML5 和 JavaScript 的开源库,它利用浏览器的MediaDevices.getUserMedia() API 访问设备摄像头,实时扫描二维码(QR Code)和条形码(Barcode),无需安装插件或 App
html5-qrcode 是一个轻量、高效、纯前端的 二维码/条形码扫描库,专为在网页(H5)中实现摄像头扫码功能而设计。

GitHub 仓库:github.com/mebjas/html...

详细用法:juejin.cn/spost/75616...

具体实现

实现效果:\

项目基于vue3框架开发:

1.安装html5-qrcode:
npm install html5-qrcode

2.页面代码实现:

html 复制代码
<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()
  }

  // 延迟确保 DOM 渲染
  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) => {
            // console.log('🎉 识别到快递单号:', 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(() => {
        // console.error('停止失败:', err)
        scanning.value = false
      })
  } else {
    scanning.value = false
  }
}

const submitForm = () => {
  ruleFormRef.value?.validate((valid) => {
    if (valid) {
      // TODO:提交事件
    } 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: 12px;
  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: 12px;
  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: 12px;
  overflow: hidden;
}
.scan-hint {
  color: #4caf50;
  margin-top: 12px;
  font-size: 18px;
  font-weight: bold;
}
.close-btn {
  margin-top: 12px;
  padding: 8px 16px;
  background: #ff5252;
  color: white;
  border: none;
  border-radius: 4px;
  font-size: 14px;
}
</style>

其他

注意事项

  1. 必须 HTTPS:生产环境必须部署在 HTTPS 域名下。
  2. 用户授权:首次使用需用户允许摄像头权限。
  3. 性能优化:避免在低性能设备上长时间运行。
  4. 兼容性问题:在某些旧版浏览器可能不支持。
  5. 移动端体验: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. 拍照上传 + 后端识别 前端 + 后端 ✅ 稳定兜底 适合弱网或兼容性差的设备
相关推荐
云枫晖1 天前
JS核心知识-模块化
前端·javascript
Asort1 天前
JavaScript设计模式(十五)——解释器模式 (Interpreter)
前端·javascript·设计模式
Java陈序员1 天前
宝藏工具站!一个轻量实用的在线工具集合!
vue.js·nuxt.js
喝西瓜汁的兔叽Yan1 天前
书架效果的实现
javascript·vue.js
GBVFtou1 天前
vue3 options模式
前端·vue.js
岁月宁静1 天前
Node.js 核心模块详解:fs 模块原理与应用
前端·人工智能·node.js
Jyywww1211 天前
uniapp uni.chooseImage+uni.uploadFile使用方法与详解
开发语言·javascript·uni-app
Cache技术分享1 天前
213. Java 函数式编程风格 - Java 中的简单 for 循环转换:从命令式到函数式
前端·后端