H5 移动端二维码扫描

H5 移动端二维码扫描-附加扫描样式

依赖包jsQR
思路:通过浏览器获取视频流播放在video当中,然后设置定时器截取视频流绘制在canvas中,使用canvas获取到图片信息,再使用jsQR解析二维码。
由于开源二维码解析库识别率不高 特别模糊的二维码识别率较低 可满足部分开发需求,如需要更加精确推荐dynamsoft
dynamsoft demo地址:https://demo.dynamsoft.com/Samples/DBR/JS/2.ui-tweaking/3.read-video-with-external-control.html?ver=latest

<template>
  <div class="test">
    <div class="fixBox">
      <div
        class="iconBox"
        @click="
          () => {
            this.$router.history.go(-1);
          }
        "
      >
        <i class="iconfont icon-fanhuitubiao"></i>
      </div>
      <div class="videoBox">
        <div class="outVideo" v-if="isAnimation">
          <video
            autoPlay
            ref="outVideo"
            webkit-playsinline
            x5-video-player-type="h5"
            x5-video-player-fullscreen="true"
            x-webkit-airplay="true"
            playsinline
            v-if="!trueFlag"
            id="myVideo"
          ></video>
        </div>
        <div class="codebg" v-if="!trueFlag">
          <div class="line"></div>
        </div>
        <canvas
          id="qr-canvas"
          style="width:6rem;height:6rem;"
          ref="canvas"
        ></canvas>
      </div>
    </div>
  </div>
</template>

<script>
import jsQR from "jsqr";
export default {
  data() {
    return {
      photoBase: "",
      trueFlag: false,
      isAnimation: true
    };
  },
  mounted() {
    this.outvideo = this.$refs.outVideo;
    this.cvsele = this.$refs.canvas;
    this.canvas = this.cvsele.getContext("2d");
    this.video = document.createElement("video");
    this.$nextTick(() => {
      this.getVideo();
    });
  },
  methods: {
    getVideo() {
      let self = this;
      try {
        navigator.getUserMedia =
          navigator.mediaDevices.getUserMedia ||
          navigator.mediaDevices.webkitGetUserMedia ||
          navigator.mediaDevices.mozGetUserMedia;
        self.URL =
          window.URL || window.webkitURL || window.mozURL || window.msURL;
        if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
          //console.log(navigator.mediaDevices.getUserMedia);
          navigator.mediaDevices
            .getUserMedia({
              video: { facingMode: { exact: "environment" } }
              // video: { facingMode: "environment" }
            })
            .then(stream => {
              this.outvideo.srcObject = stream;
              this.video.srcObject = stream;
              this.video.setAttribute("playsinline", true);
              this.video.setAttribute("webkit-playsinline", true);
              this.video.addEventListener("loadedmetadata", () => {
                this.$refs.outVideo.play();
                this.video.play();
                this.sweep();
              });
              setTimeout(() => {
                this.$refs.outVideo.play();
                this.video.play();
              }, 150);
            })
            .catch(function(err) {
              console.log(err);
              alert("请允许网站使用您的摄像头权限");
              self.$router.history.go(-1);
            });
        } else if (navigator.getUserMedia) {
          navigator
            .getUserMedia({
              video: true
            })
            .then(stream => {
              this.outvideo.srcObject = stream;
              this.video.srcObject = stream;
              this.video.setAttribute("playsinline", true);
              this.video.setAttribute("webkit-playsinline", true);
              this.video.addEventListener("loadedmetadata", () => {
                this.$refs.outVideo.play();
                this.video.play();
                this.sweep();
              });
              setTimeout(() => {
                this.$refs.outVideo.play();
                this.video.play();
              }, 150);
            })
            .catch(function(err) {
              alert(err);
            });
        }
      } catch (err) {
        console.error(err);
      }
    },
    sweep() {
      if (this.video.readyState === this.video.HAVE_ENOUGH_DATA) {
        const { videoWidth, videoHeight } = this.video;
        this.cvsele.width = videoWidth;
        this.cvsele.height = videoHeight;
        this.canvas.drawImage(this.video, 0, 0, videoWidth, videoHeight);
        try {
          const img = this.canvas.getImageData(0, 0, videoWidth, videoHeight);
          this.imgurl = img;
          const obj = jsQR(img.data, img.width, img.height, {
            inversionAttempts: "dontInvert"
          });
          console.log(obj);
          if (obj) {
            const loc = obj.location;
            this.draw(loc.topLeftCorner, loc.topRightCorner);
            this.draw(loc.topRightCorner, loc.bottomRightCorner);
            this.draw(loc.bottomRightCorner, loc.bottomLeftCorner);
            this.draw(loc.bottomLeftCorner, loc.topLeftCorner);
            if (obj.data) {
              console.info("识别结果:", obj.data);
              this.isAnimation = false;
            }
          } else {
            // console.error("识别失败,请检查二维码是否正确!");
          }
        } catch (err) {
          // console.error("识别失败,请检查二维码是否正确!", err);
        }
      }
      if (this.isAnimation) {
        this.timer = requestAnimationFrame(() => {
          this.sweep();
        });
      }
    },
    draw(begin, end) {
      this.canvas.beginPath();
      this.canvas.moveTo(begin.x, begin.y);
      this.canvas.lineTo(end.x, end.y);
      this.canvas.lineWidth = 3;
      this.canvas.strokeStyle = "red";
      this.canvas.stroke();
    },
  },
};
</script>

<style lang="scss" scoped>
.test {
  width: 100vw;
  height: 100vh;
  overflow: hidden;
}
.biginSearch {
  outline: none;
  border: none;
  width: 3.15rem;
  height: 0.8rem;
  background: var(--themeColorzc);
  border-radius: 0.1rem;
  color: #fff;
  font-weight: 700;
  margin-top: 0.3rem;
  font-size: 0.3rem;
}
.fixBox {
  position: fixed;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  // background: rgba(47, 47, 47, 0.81);
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
}
.videoBox {
  // border: 2px solid rgba(247, 241, 241, 0.81);
  // width: 6rem;
  // height: 6rem;
  // overflow: hidden;
  width: 100%;
  height: 100%;
  position: relative;
  background-color: black;
  .outVideo {
    width: 100vw;
    height: 100vh;
    position: absolute;
    top: 0;
    left: 0;
    bottom: 0;
    right: 0;
    z-index: 999;
    background-color: black;
    video {
      width: 100%;
      height: 100%;
      object-fit: fill;
    }
  }
}
canvas {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
}
.codebg {
  position: absolute;
  width: 6rem;
  height: 6rem;
  margin: 0px auto;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);

  z-index: 999;
  /*此处为了居中*/
  // background: url(img/ewm1.jpg) center top no-repeat;
  /*二维码*/
}

.line {
  position: absolute;
  left: 0px;
  z-index: 2;
  height: 3px;
  width: 6rem;
  /* background: url(img/share/dapai.png) no-repeat; */
  /*上下扫的线*/
  background-color: var(--themeColorzc);
  opacity: 0.5;
  /*动画效果*/
  animation: myScan 1s infinite alternate;
  -webkit-animation: myScan 1s infinite alternate;
}

@keyframes myScan {
  from {
    top: 0px;
  }

  to {
    top: 300px;
  }
}
@font-face {
  font-family: "iconfont"; /* Project id 2570754 */
  src: url("//at.alicdn.com/t/font_2570754_w4gqnoegfag.woff2?t=1629957776725")
      format("woff2"),
    url("//at.alicdn.com/t/font_2570754_w4gqnoegfag.woff?t=1629957776725")
      format("woff"),
    url("//at.alicdn.com/t/font_2570754_w4gqnoegfag.ttf?t=1629957776725")
      format("truetype");
}

.iconfont {
  font-family: "iconfont" !important;
  font-size: 16px;
  font-style: normal;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

.icon-fanhuitubiao:before {
  font-size: 0.48rem;
  color: #fff;
  content: "\e65c";
}
.iconBox {
  position: absolute;
  top: 0.3rem;
  left: 0.3rem;
}
</style>


你可能感兴趣的:(记录,微信,html5,javascript)