小程序web-view嵌入h5扫码 html5-qrcode库使用方法

扫码方式:使用Html5Qrcode库

1.npm install html5-qrcode
2.import { Html5Qrcode } from "html5-qrcode"; // 引入 H5 扫码库
3-1相机扫码的vue弹窗代码
vue 复制代码
   <u-overlay :show="scanShow" @click="scanShow = false" opacity="0.6">
      <view class="warp">
        <view class="rect">
          <view id="sreader" class="sreader" style="width: 100%; height: 100%">
          </view>
        </view>
        <div class="scan-wave" :class="{ active: cameraReady }"></div>
        <view class="btn">
          <u-button
            color="#AB004F"
            type="primary"
            class="next-btn"
            @click="stopScan"
            >停止扫码</u-button
          >
        </view>
      </view>
    </u-overlay>
3-2选择图片扫码
js 复制代码
<view id="reader" class="reader" style="display: none"></view>
4.点击按钮选择扫码方式
js 复制代码
    chooseScanWay() {
      uni.showActionSheet({
        itemList: ["相机扫码", "选择图片扫码"],
        success: (res) => {
          if (res.tapIndex === 0) {
            // 选择相机扫码
            console.log("1");
            this.scanShow = true;
            this.scan();
          } else if (res.tapIndex === 1) {
            // 选择图片扫码
            console.log(2);
            this.h5AlbumScan();
            // this.openAlbumScan();
          }
        },
        fail: (err) => {
          console.log("取消选择:", err);
        },
      });
    },
5-1 选择图片扫码
js 复制代码
    h5AlbumScan() {
      // 创建隐藏的文件选择框(模拟点击)
      const fileInput = document.createElement("input");
      fileInput.type = "file";
      fileInput.accept = "image/*"; // 仅允许选择图片
      fileInput.style.display = "none";

      // 监听文件选择事件
      fileInput.onchange = (e) => {
        const file = e.target.files[0];
        if (!file) return;
        const htmlCode = new Html5Qrcode("reader");
        // 解码图片中的二维码
        htmlCode
          .scanFile(file)
          .then((decodedText) => {
            console.log(decodedText, "decodedText");
            uni.showToast({ title: "扫码成功" + decodedText, icon: "success" });
          })
          .catch((err) => {
            uni.showToast({ title: "图片中未识别到二维码", icon: "none" });
            console.error("图片解码失败", err);
          });

        // 移除临时文件选择框
        document.body.removeChild(fileInput);
      };

      // 添加到页面并触发点击
      document.body.appendChild(fileInput);
      fileInput.click();
    },
5-2 相机扫码方法
js 复制代码
    scan() {
      // 定义容器尺寸(500rpx × 500rpx)
      const containerRpx = 500;
      // 转换rpx为px(核心:uniapp rpx适配公式)
      const pxPerRpx = window.innerWidth / 750;
      const containerPx = containerRpx * pxPerRpx; // 500rpx对应的实际px值

      const height = window.innerHeight;
      const width = window.innerWidth;
      const codeContent = "1024";

      Html5Qrcode.getCameras()
        .then((devices) => {
          // console.log(devices)
          this.html5QrCode = new Html5Qrcode("sreader");
          const aspectRatio = height / width;
          if (devices && devices.length) {
            // 相机启动成功后,延迟显示动画
            setTimeout(() => {
              this.cameraReady = true;
            }, 0);
            this.html5QrCode
              .start(
                { facingMode: { exact: "environment" } },
                {
                  fps: 10, // 提升帧率,不影响尺寸,仅优化识别
                  aspectRatio: aspectRatio, // 强制和扫码区域同比例,避免拉伸
                  // qrbox适配扫码区域(设为区域的80%,避免超出)
                  qrbox: {
                    width: width * 1,
                    height: height * 1,
                  },
                  videoConstraints: {
                    facingMode: "environment",
                    // 强制视频流尺寸不超过扫码区域,避免溢出
                    // width: { ideal: width, max: width },
                    // height: { ideal: height, max: height },
                    aspectRatio: aspectRatio, // 锁定比例,杜绝拉伸溢出
                  },
                  // 保留条形码识别优化(无兼容问题)
                  disableAutoFocus: true, // 开启自动对焦,画面清晰
                  tryHarder: true, // 深度识别,兼容条形码
                },
                (decodedText, decodedResult) => {
                  // do something when code is read
                  console.log("decodedText", decodedText);
                  uni.showToast({
                    title: decodedText,
                    icon: "none",
                  });
                  // console.log('decodedResult', decodedResult)
                },
                (errorMessage) => {
                  // parse error, ignore it.
                  // console.log('parse error, ignore it.', errorMessage)
                },
              )
              .catch((err) => {
                // Start failed, handle it.
                console.log("Start failed, handle it.");
              });
          }
        })
        .catch((err) => {
          // handle err
          console.log(err);
          uni.showToast({
            title: err,
            icon: "none",
          });
        });
    },
6.扫码完成需要关闭摄像头
js 复制代码
    stopScan() {
      if (this.html5QrCode) {
        this.html5QrCode
          .stop()
          .then(() => {
            console.log("摄像头已关闭");
            this.scanShow = false;
            this.html5QrCode = null;
          })
          .catch((err) => {
            console.error("关闭摄像头失败", err);
          });
      } else {
        this.scanShow = false;
      }
    },
7.扫码模块样式
css 复制代码
.warp {
  display: flex;
  align-items: center;
  // justify-content: center;
  // padding-top: 50%;
  height: 100vh;
  flex-direction: column;
}
.btn {
  // padding-top: 100rpx;
  position: absolute;
  bottom: 100rpx;
}
.rect {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  // background-color: #fff;
  //    background:
  //   /* 左上角:横向 + 纵向 */
  //   linear-gradient(#007aff, #007aff) 0 0 / 40rpx 10rpx no-repeat,
  //   linear-gradient(#007aff, #007aff) 0 0 / 10rpx 40rpx no-repeat,
  //   /* 右上角:横向 + 纵向 */
  //   linear-gradient(#007aff, #007aff) 100% 0 / 40rpx 10rpx no-repeat,
  //   linear-gradient(#007aff, #007aff) 100% 0 / 10rpx 40rpx no-repeat,
  //   /* 左下角:横向 + 纵向 */
  //   linear-gradient(#007aff, #007aff) 0 100% / 40rpx 10rpx no-repeat,
  //   linear-gradient(#007aff, #007aff) 0 100% / 10rpx 40rpx no-repeat,
  //   /* 右下角:横向 + 纵向 */
  //   linear-gradient(#007aff, #007aff) 100% 100% / 40rpx 10rpx no-repeat,
  //   linear-gradient(#007aff, #007aff) 100% 100% / 10rpx 40rpx no-repeat;
  // background-color: #fff; /* 基础背景色 */
  background-color: transparent;
  .sreader {
    position: absolute;
  }
}
/* 扫描波纹/扫描线样式 */
.scan-wave {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 1rpx; /* 扫描线粗细 */
  // will-change: transform;
  //   backface-visibility: hidden;
  transform: translateZ(0);
  background: linear-gradient(
    90deg,
    transparent,
    #07c160,
    /* 微信绿 */ #07c160,
    transparent
  );
  border-radius: 50%;
  /* 微信风格光晕:柔和的绿色光晕 */
  box-shadow: 0 0 30rpx 10rpx rgba(7, 193, 96, 0.3);
  pointer-events: none; /* 避免遮挡交互 */
  z-index: 2; /* 层级高于视频,低于角标 */
  /* 核心动画:从顶部滚动到底部 */
  animation: scanMove 3s linear infinite;
  animation-play-state: paused; /* 默认暂停 */
}
.scan-wave.active {
  animation-play-state: running; /* 相机就绪后播放 */
}

/* 扫描线滚动动画 */
@keyframes scanMove {
  0% {
    top: 0; /* 顶部起始位置 */
    opacity: 1; /* 初始完全不透明 */
  }
  85% {
    top: 85%; /* 接近底部 */
    opacity: 1;
  }

  100% {
    top: 100%; /* 停在底部 */
    opacity: 1;
  }
}
相关推荐
不懂代码的切图仔2 小时前
小程序web-view嵌入h5扫码 jssdk方式
前端·微信小程序
软弹2 小时前
Vue2、Vue3、React 状态管理全方位对比
前端·javascript·vue.js·react.js
王启年2 小时前
npm link 详解:本地包开发与测试的利器
前端
Presto2 小时前
HMR 是为人类设计的,不是为 Agent 设计的
前端
吃素的老虎2 小时前
从零构建 AI 网关(三):渠道插件系统
前端
学以智用2 小时前
# Vue3 路由(Vue Router 4)完全指南
前端·vue.js
anyup2 小时前
弃用 vue-i18n?只用 uView Pro 我照样做国际化!
前端·架构·uni-app
大漠_w3cpluscom2 小时前
利用现代 CSS 实现区间选择
前端·css·html
吃素的老虎2 小时前
从零构建 AI 网关(一):WebSocket 服务器实战
前端