效果图如下

本文将详细介绍如何使用 nvue + Barcode 模块实现一个完整的自定义扫码页面。
为什么选择 nvue?
因为uniapp中这个组件的限制

配置:
首先需要在 `manifest.json` 中启用 Barcode 模块:
 


{
  "app-plus": {
    "modules": {
      "Barcode": {},
      "Camera": {}
    },
    "distribute": {
      "android": {
        "permissions": [
          "<uses-permission android:name=\"android.permission.CAMERA\"/>"
        ]
      }
    }
  }
}

2. pages.json 配置

在 `pages.json` 中注册页面并隐藏导航栏:


{
  "path": "pages/Shops/code",
  "style": {
    "navigationBarTitleText": "扫一扫",
    "app-plus": {
      "titleNView": false
    }
  }
}

页面完整代码

<template>
  <view class="page">
    <!-- 状态栏占位 -->
    <view class="status-bar" :style="{ height: statusBarHeight + 'px' }"></view>
    
    <!-- 自定义导航栏 -->
    <view class="nav-bar">
      <view class="nav-back" @click="goBack">
        <uni-icons type="left" size="18" color="#333333"></uni-icons>
      </view>
      <text class="nav-title">订单核销</text>
      <view class="nav-placeholder"></view>
    </view>
    
    <!-- 扫码区域容器 -->
    <view class="scan-container">
      <!-- Barcode 组件 -->
      <barcode 
        ref="barcode" 
        class="barcode" 
        :autostart="false" 
        @marked="onMarked" 
        @error="onError">
      </barcode>
      
      <!-- 底部提示 -->
      <view class="bottom-tip" @click="goToManualInput">
        <text class="tip-text">无法识别?试试</text>
        <text class="tip-link">手动输入核销码</text>
      </view>
    </view>
  </view>
</template>

Js逻辑代码

export default {
  data() {
    return {
      statusBarHeight: 0,
      isScanning: false // 防止重复扫码
    }
  },
  
  created() {
    // 获取状态栏高度,适配不同机型
    const systemInfo = uni.getSystemInfoSync();
    this.statusBarHeight = systemInfo.statusBarHeight || 0;
  },
  
  onReady() {
    // 页面首次加载时启动扫码
    this.startScan();
  },
  
  onShow() {
    // 页面显示时重新启动扫码(处理返回场景)
    this.isScanning = false;
    this.startScan();
  },
  
  methods: {
    // 启动扫码
    startScan() {
      this.$nextTick(() => {
        try {
          const barcode = this.$refs.barcode;
          if (barcode && barcode.start) {
            barcode.start();
            console.log('扫码已启动');
          }
        } catch (e) {
          console.log('启动扫码失败:', e);
        }
      });
    },
    
    // 扫码成功回调
    onMarked(e) {
      // 防止重复处理
      if (this.isScanning) {
        return;
      }
      this.isScanning = true;
      
      const result = e.detail.code;
      console.log('扫码结果:', result);
      
      // 处理扫码结果
      this.handleScanResult(result);
      
      // 延迟重置标志
      setTimeout(() => {
        this.isScanning = false;
      }, 2000);
    },
    
    // 扫码失败回调
    onError(e) {
      console.log('扫码错误:', e);
      uni.showToast({
        title: '扫码失败',
        icon: 'none'
      });
    },
    
    // 处理扫码结果
    handleScanResult(code) {
      // 跳转到处理页面或调用接口
      uni.navigateTo({
        url: '/pages/result?code=' + code
      });
    },
    
    // 手动输入
    goToManualInput() {
      uni.navigateTo({
        url: '/pages/manualInput'
      });
    },
    
    // 返回
    goBack() {
      uni.navigateBack({});
    }
  }
}

关于css就不公布了,大家可以自己定义。

遇到的一些问题:
1.页面黑屏(考虑Barcode 组件未正确启动)

// 确保在 $nextTick 中启动
this.$nextTick(() => {
  const barcode = this.$refs.barcode;
  if (barcode && barcode.start) {
    barcode.start();
  }
});

2.扫码后卡死(扫码成功后组件未停止,继续占用摄像头)

- 使用 `isScanning` 标志防止重复处理

- 在 `onShow` 中重置状态

3.返回后无法扫码(autostart 只在首次加载时生效)

onShow() {

  this.startScan(); // 手动重启

}

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐