鸿蒙OS&UniApp 实现的二维码扫描与生成组件#三方框架 #Uniapp

UniApp 实现的二维码扫描与生成组件

前言

最近在做一个电商小程序时,遇到了需要扫描和生成二维码的需求。在移动应用开发中,二维码功能已经成为标配,特别是在电商、社交和支付等场景下。UniApp作为一个跨平台开发框架,为我们提供了便捷的方式来实现这些功能。本文将分享我在项目中实现二维码扫描与生成的经验和技术细节,希望能给大家一些启发。

需求分析

在我的项目中,主要有两个核心需求:

  1. 二维码扫描:用户需要扫描商品二维码获取商品信息,或扫描会员卡二维码实现快速登录。
  2. 二维码生成:系统需要为每个商品、订单以及用户生成专属二维码,便于信息分享和快速查询。

这两个看似简单的功能,实际开发中却有不少细节需要注意。下面我将分享实现过程中的关键点和代码实现。

二维码扫描功能实现

UniApp提供了原生扫码API,但在使用过程中我发现其在不同平台上的表现并不一致,特别是在样式和交互体验上。因此,我决定使用第三方插件来增强扫码体验。

1. 基础环境搭建

首先,我们需要安装必要的依赖:

bash 复制代码
npm install uqrcode --save

2. 封装扫码组件

我创建了一个通用的扫码组件,以便在不同页面复用:

vue 复制代码
<template>
  <view class="scanner-container">
    <camera 
      v-if="showCamera" 
      device-position="back" 
      flash="auto" 
      @error="handleError"
      @scancode="handleScanCode"
      class="scanner-camera">
      <cover-view class="scanner-mask">
        <cover-view class="scanner-frame"></cover-view>
      </cover-view>
    </camera>
    <view v-if="!showCamera" class="scanner-placeholder">
      <button type="primary" @tap="startScan">开始扫码</button>
    </view>
  </view>
</template>

<script>
export default {
  data() {
    return {
      showCamera: false,
      scanResult: '',
      isScanning: false
    }
  },
  methods: {
    startScan() {
      this.showCamera = true;
      this.isScanning = true;
      
      // 兼容处理不同平台
      // #ifdef APP-PLUS
      this.startAppScan();
      // #endif
      
      // #ifdef MP-WEIXIN || MP-ALIPAY
      this.startMpScan();
      // #endif
    },
    
    startAppScan() {
      // App端使用plus接口实现
      const self = this;
      plus.barcode.scan('', (type, result) => {
        self.handleScanResult(result);
      }, (error) => {
        uni.showToast({
          title: '扫码失败: ' + error.message,
          icon: 'none'
        });
        self.showCamera = false;
      });
    },
    
    startMpScan() {
      // 小程序端依赖camera组件的scancode事件
      // 小程序端不需要额外处理,依赖template中的camera组件
    },
    
    handleScanCode(e) {
      if (this.isScanning) {
        this.isScanning = false;
        this.handleScanResult(e.detail.result);
      }
    },
    
    handleScanResult(result) {
      this.scanResult = result;
      this.showCamera = false;
      this.$emit('onScanSuccess', result);
    },
    
    handleError(e) {
      uni.showToast({
        title: '相机启动失败,请检查权限设置',
        icon: 'none'
      });
      this.showCamera = false;
    }
  }
}
</script>

<style>
.scanner-container {
  width: 100%;
  height: 600rpx;
  position: relative;
}
.scanner-camera {
  width: 100%;
  height: 100%;
}
.scanner-mask {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.5);
  display: flex;
  justify-content: center;
  align-items: center;
}
.scanner-frame {
  width: 500rpx;
  height: 500rpx;
  background-color: transparent;
  border: 4rpx solid #2979ff;
}
.scanner-placeholder {
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  background-color: #f5f5f5;
}
</style>

上面的代码创建了一个通用的扫码组件,它能够适配App和小程序两种环境。值得注意的是,我使用了条件编译(#ifdef)来处理不同平台的差异,这是UniApp的一大优势。

3. 使用扫码组件

在实际页面中使用这个组件非常简单:

vue 复制代码
<template>
  <view class="container">
    <view class="header">商品扫码</view>
    <qr-scanner @onScanSuccess="handleScanResult"></qr-scanner>
    <view class="result" v-if="scanResult">
      <text>扫描结果: {{scanResult}}</text>
    </view>
  </view>
</template>

<script>
import QrScanner from '@/components/QrScanner.vue';

export default {
  components: {
    QrScanner
  },
  data() {
    return {
      scanResult: ''
    }
  },
  methods: {
    handleScanResult(result) {
      this.scanResult = result;
      // 处理扫码结果,例如解析商品ID并跳转到商品详情页
      this.processQrCode(result);
    },
    processQrCode(code) {
      try {
        // 假设二维码内容是JSON格式
        const data = JSON.parse(code);
        if (data.type === 'product') {
          uni.navigateTo({
            url: `/pages/product/detail?id=${data.id}`
          });
        } else if (data.type === 'order') {
          uni.navigateTo({
            url: `/pages/order/detail?id=${data.id}`
          });
        }
      } catch (e) {
        // 处理非JSON格式的二维码
        uni.showToast({
          title: '无法识别的二维码格式',
          icon: 'none'
        });
      }
    }
  }
}
</script>

二维码生成功能实现

生成二维码相对于扫描来说更为简单,但也有一些需要注意的点,特别是在样式自定义方面。

1. 基础二维码生成

我使用了uQRCode这个库来生成二维码,它支持自定义颜色、大小和纠错级别等:

vue 复制代码
<template>
  <view class="qrcode-container">
    <canvas canvas-id="qrcode" id="qrcode" class="qrcode-canvas"></canvas>
    <button type="primary" @tap="saveQrCode">保存二维码</button>
  </view>
</template>

<script>
import UQRCode from 'uqrcode';

export default {
  props: {
    content: {
      type: String,
      required: true
    },
    size: {
      type: Number,
      default: 200
    },
    margin: {
      type: Number,
      default: 10
    },
    backgroundColor: {
      type: String,
      default: '#ffffff'
    },
    foregroundColor: {
      type: String,
      default: '#000000'
    }
  },
  data() {
    return {
      qrUrl: ''
    }
  },
  mounted() {
    this.generateQrCode();
  },
  methods: {
    generateQrCode() {
      // 生成二维码
      UQRCode.make({
        canvasId: 'qrcode',
        componentInstance: this,
        text: this.content,
        size: this.size,
        margin: this.margin,
        backgroundColor: this.backgroundColor,
        foregroundColor: this.foregroundColor,
        success: (res) => {
          this.qrUrl = res;
        },
        fail: (error) => {
          console.error('二维码生成失败', error);
          uni.showToast({
            title: '生成二维码失败',
            icon: 'none'
          });
        }
      });
    },
    saveQrCode() {
      // 保存二维码到相册
      uni.canvasToTempFilePath({
        canvasId: 'qrcode',
        success: (res) => {
          uni.saveImageToPhotosAlbum({
            filePath: res.tempFilePath,
            success: () => {
              uni.showToast({
                title: '二维码已保存到相册'
              });
            },
            fail: (err) => {
              console.error('保存失败', err);
              uni.showToast({
                title: '保存失败,请检查相册权限',
                icon: 'none'
              });
            }
          });
        },
        fail: (err) => {
          console.error('导出图片失败', err);
        }
      }, this);
    }
  },
  watch: {
    content() {
      // 当内容变化时重新生成二维码
      this.$nextTick(() => {
        this.generateQrCode();
      });
    }
  }
}
</script>

<style>
.qrcode-container {
  padding: 30rpx;
  display: flex;
  flex-direction: column;
  align-items: center;
}
.qrcode-canvas {
  width: 400rpx;
  height: 400rpx;
  margin-bottom: 30rpx;
}
</style>

2. 高级定制化二维码

在某些场景下,我们需要在二维码中嵌入logo或者应用特定的样式。以下是带有logo的二维码生成代码:

js 复制代码
generateQrCodeWithLogo() {
  const that = this;
  // 先生成普通二维码
  UQRCode.make({
    canvasId: 'qrcode',
    componentInstance: this,
    text: this.content,
    size: this.size,
    margin: this.margin,
    backgroundColor: this.backgroundColor,
    foregroundColor: this.foregroundColor,
    success: () => {
      // 然后在二维码中间绘制logo
      const ctx = uni.createCanvasContext('qrcode', that);
      // 计算logo大小和位置
      const logoSize = that.size / 5;
      const logoX = (that.size - logoSize) / 2;
      const logoY = (that.size - logoSize) / 2;
      
      // 绘制白色背景
      ctx.setFillStyle('#ffffff');
      ctx.fillRect(logoX - 2, logoY - 2, logoSize + 4, logoSize + 4);
      
      // 绘制logo图片
      ctx.drawImage('/static/logo.png', logoX, logoY, logoSize, logoSize);
      ctx.draw(true, () => {
        // 导出为图片URL
        uni.canvasToTempFilePath({
          canvasId: 'qrcode',
          success: (res) => {
            that.qrUrl = res.tempFilePath;
          },
          fail: (err) => {
            console.error('导出失败', err);
          }
        }, that);
      });
    }
  });
}

实际应用案例

我在一个线下门店管理系统中应用了上述技术,实现了以下功能:

  1. 店铺会员卡二维码:生成包含会员信息的二维码,用户可以保存到手机相册或添加到微信卡包。

  2. 商品快速查询:门店员工可以扫描商品二维码,快速查询库存和价格信息。

  3. 订单核销系统:用户下单后,系统生成订单二维码,用户到店出示,店员扫码即可完成核销。

这些功能大大提升了用户体验和门店运营效率。特别是订单核销系统,将原本需要几分钟的流程缩短至几秒钟,同时避免了手工录入可能带来的错误。

踩坑记录与解决方案

在实现过程中,我遇到了一些问题,在此分享解决方案:

  1. 相机权限问题:在Android上,有时相机初始化失败。解决方法是在manifest.json中明确申请相机权限,并在使用前进行权限检查:
js 复制代码
checkCameraPermission() {
  // #ifdef APP-PLUS
  const self = this;
  const currentOS = plus.os.name;
  
  if (currentOS == 'Android') {
    plus.android.requestPermissions(
      ['android.permission.CAMERA'],
      function(resultObj) {
        if (resultObj.granted.length > 0) {
          self.startScan();
        } else {
          uni.showToast({
            title: '请授予相机权限以使用扫码功能',
            icon: 'none'
          });
        }
      }
    );
  } else {
    self.startScan();
  }
  // #endif
  
  // #ifdef MP
  this.startScan();
  // #endif
}
  1. iOS扫码闪光灯控制:在iOS上控制闪光灯需要使用原生API:
js 复制代码
// #ifdef APP-PLUS
toggleFlashlight() {
  if (plus.os.name == 'iOS') {
    // iOS特殊处理
    const CVCaptureDevice = plus.ios.importClass('AVCaptureDevice');
    const device = CVCaptureDevice.defaultDeviceWithMediaType('vide');
    
    if (device.hasTorch()) {
      if (device.torchMode() == 0) {
        device.lockForConfiguration();
        device.setTorchMode(1);
        device.unlockForConfiguration();
      } else {
        device.lockForConfiguration();
        device.setTorchMode(0);
        device.unlockForConfiguration();
      }
    }
  }
}
// #endif
  1. 二维码生成清晰度问题:在高像素密度的屏幕上,生成的二维码可能显得模糊。解决方法是设置更高的尺寸并使用缩放:
js 复制代码
// 设置更高的尺寸并缩放
UQRCode.make({
  canvasId: 'qrcode',
  componentInstance: this,
  text: this.content,
  size: this.size * 2, // 设置2倍大小
  margin: this.margin,
  success: () => {
    // Canvas绘制完成后,通过样式控制显示大小
    // CSS中设置实际显示大小
  }
});

总结

通过UniApp实现二维码扫描与生成功能相对简单,但在跨平台兼容性和用户体验优化方面还需要一些额外工作。在实际项目中,我们需要:

  1. 充分利用条件编译,处理各平台差异
  2. 考虑权限管理和错误处理
  3. 注重交互体验和视觉效果
  4. 对复杂场景进行适当的定制开发

正确实现二维码功能可以显著提升应用的实用性和用户体验,也是现代移动应用不可或缺的一部分。

希望本文对你在UniApp中实现二维码功能有所帮助。如有疑问或补充,欢迎在评论区讨论交流!

相关推荐
a_靖21 分钟前
uniapp使用全局组件,
uni-app·全局组件
lqj_本人1 小时前
鸿蒙OS&UniApp制作一个小巧的图片浏览器#三方框架 #Uniapp
华为·uni-app·harmonyos
向明天乄2 小时前
uni-app微信小程序登录流程详解
微信小程序·uni-app
lqj_本人4 小时前
鸿蒙OS&UniApp 开发的下拉刷新与上拉加载列表#三方框架 #Uniapp
华为·uni-app·harmonyos
lqj_本人5 小时前
鸿蒙OS&UniApp 制作个人信息编辑界面与头像上传功能#三方框架 #Uniapp
uni-app·harmonyos
老李不敲代码7 小时前
榕壹云打车系统:基于Spring Boot+MySQL+UniApp的开源网约车解决方案
spring boot·mysql·微信小程序·uni-app·软件需求
lqj_本人11 小时前
鸿蒙OS&UniApp 开发实时聊天页面的最佳实践与实现#三方框架 #Uniapp
uni-app
不法20 小时前
uniapp 百家云直播插件打包失败
uni-app·插件使用
moxiaoran57531 天前
uni-app学习笔记五-vue3响应式基础
笔记·学习·uni-app