vue-qrcode-reader实现简单的实时扫一扫功能

1. 下载与安装插件vue-qecode-reader

  官网:https://gruhn.github.io/vue-qrcode-reader/demos/Simple.html

npm install --save vue-qecode-reader
或者 cnpm install --save vue-qrcode-reader

2.实现

1.QrcodeReader.vue

camera 有着以下属性:

  rear: 当camera为rear值的时候调用前摄像头;

  front: 当camera为front值的时候调用后摄像头;

  off: 当camera为off值的时候调用关闭摄像头,会获取最后一帧用于显示;

  auto: 是用于开始获取摄像头,也是默认属性。

torch 的属性是布尔值,当为

  true的时候打开手电筒,

  false是关闭摄像头。

 

<template>
    <div class="qrcode">
        <div class="code">
            <div class="qrcode-drop-zone" v-show="qrcode">
                <!-- decode是扫描结果的函数,torch用于是否需要打开手电筒,init用于检查该设备是否能够调用摄像头的权限,camera可用于打开前面或者后面摄像头  -->
                <qrcode-drop-zone @decode="onDecode">
                    <qrcode-stream @decode="onDecode" :torch="torchActive" @init="onInit" :camera="camera">
                            <div class="qr-scanner">
                                <div class="box">
                                    <div class="line"></div>
                                    <div class="angle"></div>
                                </div>
                            </div>
                    </qrcode-stream>
                </qrcode-drop-zone>
            </div>
            <div class="code-button">
                <van-button type="info" @click="switchCamera" plain>相机反转</van-button>
                <!-- <van-button type="info" @click="ClickFlash" plain>打开手电筒</van-button> -->
                <van-button type="info" @click="turnCameraOff" plain>
                    {{ qrcode === true ? '关闭相机' : '打开相机' }}
                </van-button>
            </div>
        </div>
    </div>
</template>

<script>
// 引用vue-qrcode-reader插件
import { QrcodeStream, QrcodeDropZone } from 'vue-qrcode-reader'

export default {
    name: 'Approve',
    props: {
        camera: {
            type: String,
            default: 'rear'
        },
        torchActive: {
            type: Boolean,
            default: false
        },
        qrcode: {
            type: Boolean,
            default: false
        },
        noStreamApiSupport: {
            type: Boolean,
            default: false
        }
    },
    data () {
        return { error: '' }
    },
    created () {},

    components: {
        // 注册组件
        QrcodeStream,
        QrcodeDropZone
        // QrcodeCapture
    },
    methods: {
        // 扫码结果回调
        onDecode (result) {
            this.$emit('onDecode', result)
        },
        // 相机反转
        switchCamera () {
            this.$emit('switchCamera')
        },
        // 关闭、打开相机
        turnCameraOff () {
            this.$emit('turnCameraOff')
        },
        // 打开手电筒
        ClickFlash () {
            this.$emit('ClickFlash')
        },
        // 检查是否调用摄像头
        onInit (promise) {
            this.$emit('onInit', promise)
        }
    }
}
</script>
<style lang="scss" scoped>
::v-deep {
    .qrcode-stream-camera {
        height: 85vh;
    }
}
.code {
    // width: 500px;
    // height: 500px;
    width: 100%;
    height: 100%;
    margin: 88px auto 0;
    .qrcode-drop-zone {
        width: 100%;
        height: 85vh;
        margin: 0 auto;
          background: #000;
    }
    .code-button {
        width: 100%;
        position: fixed;
        left: 0;
        bottom: 10px;
        display: flex;
        .van-button {
            flex: 1;
            border: none;
        }
    }

    .qr-scanner {
    width: 100%;
    height: 85vh;
      background-image:
        linear-gradient(0deg,
          transparent 24%,
          rgba(32, 255, 77, 0.1) 25%,
          rgba(32, 255, 77, 0.1) 26%,
          transparent 27%,
          transparent 74%,
          rgba(32, 255, 77, 0.1) 75%,
          rgba(32, 255, 77, 0.1) 76%,
          transparent 77%,
          transparent),
        linear-gradient(90deg,
          transparent 24%,
          rgba(32, 255, 77, 0.1) 25%,
          rgba(32, 255, 77, 0.1) 26%,
          transparent 27%,
          transparent 74%,
          rgba(32, 255, 77, 0.1) 75%,
          rgba(32, 255, 77, 0.1) 76%,
          transparent 77%,
          transparent);
      background-size: 3rem 3rem;
      background-position: -1rem -1rem;
      position: relative;
      background-color: #1110;

      /* background-color: #111; */
    }

    .qr-scanner .box {
      width: 100%;
      height: 100%;
      position: absolute;
      left: 50%;
      top: 50%;
      transform: translate(-50%, -50%);
      overflow: hidden;
      /* background: url('http://resource.beige.world/imgs/gongconghao.png') no-repeat center center; */
    }

    .qr-scanner .line {
      height: calc(100% - 2px);
      width: 100%;
      background: linear-gradient(180deg, rgba(0, 255, 51, 0) 43%, #00ff33 211%);
      border-bottom: 3px solid #00ff33;
      transform: translateY(-100%);
      animation: radar-beam 2s infinite alternate;
      animation-timing-function: cubic-bezier(0.53, 0, 0.43, 0.99);
      animation-delay: 1.4s;
    }

    .qr-scanner .box:after,
    .qr-scanner .box:before,
    .qr-scanner .angle:after,
    .qr-scanner .angle:before {
      content: '';
      display: block;
      position: absolute;
      width: 3vw;
      height: 3vw;

      border: 0.2rem solid transparent;
    }

    .qr-scanner .box:after,
    .qr-scanner .box:before {
      top: 0;
      border-top-color: #00ff33;
    }

    .qr-scanner .angle:after,
    .qr-scanner .angle:before {
      bottom: 0;
      border-bottom-color: #00ff33;
    }

    .qr-scanner .box:before,
    .qr-scanner .angle:before {
      left: 0;
      border-left-color: #00ff33;
    }

    .qr-scanner .box:after,
    .qr-scanner .angle:after {
      right: 0;
      border-right-color: #00ff33;
    }

    @keyframes radar-beam {
      0% {
        transform: translateY(-100%);
      }

      100% {
        transform: translateY(0);
      }
    }
}
</style>
 

2.index.vue

<template>
    <div class="qrcode">
        <div class="box">
            <qrcode
                :qrcode="qrcode"
                :camera="camera"
                :torchActive="torchActive"
                @switchCamera="switchCamera"
                @ClickFlash="ClickFlash"
                @turnCameraOff="turnCameraOff"
                @onDecode="onDecode"
                @onInit="onInit"
            />
        </div>
    </div>
</template>
<script>
export default {
    data () {
        return {
            qrcode: true,
            torchActive: false,
            camera: 'front'
        }
    },
    mounted () {},
    methods: {
        // 打开相机
        clickCode () {
            // camera:: 'rear'--前摄像头,'front'后摄像头,'off'关闭摄像头,会获取最后一帧显示,'auto'开始获取摄像头
            this.qrcode = true
            this.camera = 'rear'
        },
        // 扫码结果回调
        onDecode (result) {
            console.log(result)
            this.turnCameraOff()
        },
        // 相机反转
        switchCamera () {
            switch (this.camera) {
            case 'front':
                this.camera = 'rear'
                break
            case 'rear':
                this.camera = 'front'
                break
            default:
                this.$toast('错误')
            }
        },
        // 关闭相机??????
        turnCameraOff () {
            // this.camera = 'off'
            this.qrcode = !this.qrcode
            if (this.camera === 'off') {
                this.camera = 'front'
            } else {
                this.camera = 'off'
            }
        },
        // 打开手电筒
        ClickFlash () {
            switch (this.torchActive) {
            case true:
                this.torchActive = false
                break
            case false:
                this.torchActive = true
                break
            default:
                this.$toast('错误')
            }
        },

        // 检查是否调用摄像头
        async onInit (promise) {
            try {
                await promise
            } catch (error) {
                if (error.name === 'StreamApiNotSupportedError') {
                } else if (error.name === 'NotAllowedError') {
                    this.errorMessage = 'Hey! I need access to your camera'
                } else if (error.name === 'NotFoundError') {
                    this.errorMessage = 'Do you even have a camera on your device?'
                } else if (error.name === 'NotSupportedError') {
                    this.errorMessage =
                        'Seems like this page is served in non-secure context (HTTPS, localhost or file://)'
                } else if (error.name === 'NotReadableError') {
                    this.errorMessage = "Couldn't access your camera. Is it already in use?"
                } else if (error.name === 'OverconstrainedError') {
                    this.errorMessage =
                        "Constraints don't match any installed camera. Did you asked for the front camera although there is none?"
                } else {
                    this.errorMessage = 'UNKNOWN ERROR: ' + error.message
                }
            }
        }
    },
    components: {
        qrcode: () => import('./qrcode-reader.vue')
    }
}
</script>
<style lang="scss" scoped>
.qrcode {
    .box {
        width: 100%;
    }
}
</style>

3.注意点

  1. 调用的是浏览器的摄像头

  2. 该插件只适用于扫描二维码,而不适用于扫描条形码。

  3. vue-qrcode-reader这个插件只适用于本地调试或者带有https的域名,http是不能用这个插件的。具体原因请查看官方文档
  4. 附:前端开发本地搭建https环境

     
posted @   CHUNYIN  阅读(3480)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端
点击右上角即可分享
微信分享提示