Vue 扫描二维码、条形码

Vue + zxing 实现扫二维码、条形码功能

zXing :一个开源的、多格式的一维/二维条码图像处理库; 地址: https://github.com/zxing-js/library

官方提供的多种扫描案例:https://zxing-js.github.io/library/

注意: Zxing 只能运行在 'localhost' 或者 ‘https’ 域名下(webRTC必须在https环境下运行);

使用 zxing 前提 :必须保证摄像头正常,我们可以打开相机测试相机是否可用,如果可用请跳过直接看下面的实现代码;

如果在打开相机时,发现提示"找不到你的相机",打开 设备管理器 也找不到 照相机 ,可参考下面的解决办法;
在这里插入图片描述
解决办法:直接 Fn+F6 键(不同的电脑按键可能不一样,记得找摄像头标识的按键),然后稍等一会发现 设备管理器 出现了 照相机 !!


安装插件

  npm install @zxing/library
  npm install --save webrtc-adapter  

案例一、
vue 扫描二维码 条形码

<template>
    <div class="page-scan">
        <!-- 扫码区域 -->
        <div class="QrCode">
            <video ref="video" height="100%" width="100%" id="video" autoplay></video>
        </div>
        <!-- 扫码样式一 -->
        <div class="Qr_scanner">
            <div class="box">
                <div class="line_row">
                    <div class="line"></div>
                </div>
                <div class="angle"></div>
            </div>
        </div>

    </div>
</template>
  
<script>
// WebRTC适配器 只需要引入就ok
import 'webrtc-adapter'
import { BrowserMultiFormatReader } from '@zxing/library'
export default {
    name: 'scanCodePage',
    data() {
        return {
            codeReader: null
        }
    },
    mounted() {
        this.codeReader = new BrowserMultiFormatReader()
        this.openScan()
    },
    beforeUnmount() {
        this.codeReader && this.codeReader.reset()
    },
    methods: {
        async openScan() {
            this.codeReader
                .listVideoInputDevices()
                .then((videoInputDevices) => {
                    // 默认获取第一个摄像头设备id
                    let firstDeviceId = videoInputDevices[0].deviceId
                    // 获取第一个摄像头设备的名称
                    const videoInputDeviceslablestr = JSON.stringify(
                        videoInputDevices[0].label
                    )
                    if (videoInputDevices.length > 1) {
                        // 判断是否后置摄像头
                        if (videoInputDeviceslablestr.indexOf('back') > -1) {
                            firstDeviceId = videoInputDevices[0].deviceId
                        } else {
                            firstDeviceId = videoInputDevices[1].deviceId
                        }
                    }
                    this.codeReader && this.codeReader.reset() // 重置
                    this.decodeFromInputVideoFunc(firstDeviceId)
                })
                .catch((err) => {
                    console.error(err)
                })
        },
        decodeFromInputVideoFunc(firstDeviceId) {
            this.codeReader.decodeFromInputVideoDeviceContinuously(
                firstDeviceId,
                'video',
                (result, err) => {
                    if (result) {
                        console.log('扫描结果', result)
                        // if (result.text) {
                        //     this.clickIndexLeft(result.text)
                        // }
                    }
                    if (err && !err) {
                        console.error(err)
                    }
                }
            )
        },
        // 停止扫描,并返回上一页
        clickIndexLeft(result) {
            this.codeReader && this.codeReader.reset()
            this.codeReader = null
            // this.$route.params.result = result
            // this.$router.back()
        }
    }
}
</script>
  
<style lang="scss" scope>
.QrCode {
    width: 100vw;
    height: 100vh;
    position: relative;
    #video {
        width: 100%;
        height: 100%;
        object-fit: cover;
    }
}

.Qr_scanner {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 9;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.5);
}
.Qr_scanner .box {
    width: 75vw;
    height: 75vw;
    max-height: 75vh;
    max-width: 75vh;
    position: relative;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    border: 1px solid rgb(43, 113, 254);
    .line_row {
        width: 100%;
        overflow: hidden;
        background-image: linear-gradient(
                0deg,
                transparent 24%,
                rgba(136, 176, 255, 0.1) 25%,
                rgba(136, 176, 255, 0.1) 26%,
                transparent 27%,
                transparent 74%,
                rgba(136, 176, 255, 0.1) 75%,
                rgba(136, 176, 255, 0.1) 76%,
                transparent 77%,
                transparent
            ),
            linear-gradient(
                90deg,
                transparent 24%,
                rgba(136, 176, 255, 0.1) 25%,
                rgba(136, 176, 255, 0.1) 26%,
                transparent 27%,
                transparent 74%,
                rgba(136, 176, 255, 0.1) 75%,
                rgba(136, 176, 255, 0.1) 76%,
                transparent 77%,
                transparent
            );
        background-size: 3rem 3rem;
        background-position: -1rem -1rem;
        animation: Heightchange 2s infinite;
        animation-timing-function: cubic-bezier(0.53, 0, 0.43, 0.99);
        animation-delay: 1.4s;
        border-bottom: 1px solid rgba(136, 176, 255, 0.1);
        display: flex;
        justify-content: center;
        align-items: flex-end;
    }
}
.Qr_scanner .line {
    width: 100%;
    height: 3px;
    background: #2b71fe;
    // opacity: 0.58;
    filter: blur(4px);
}
.Qr_scanner .box:after,
.Qr_scanner .box:before,
.Qr_scanner .angle:after,
.Qr_scanner .angle:before {
    content: '';
    display: block;
    position: absolute;
    width: 78px;
    height: 78px;
    border: 0.3rem solid transparent;
}
.Qr_scanner .box:after,
.Qr_scanner .box:before {
    top: -7px;
    border-top-color: #2b71fe;
}
.Qr_scanner .angle:after,
.Qr_scanner .angle:before {
    bottom: -7px;
    border-bottom-color: #2b71fe;
}
.Qr_scanner .box:before,
.Qr_scanner .angle:before {
    left: -7px;
    border-left-color: #2b71fe;
}
.Qr_scanner .box:after,
.Qr_scanner .angle:after {
    right: -7px;
    border-right-color: #2b71fe;
}
@keyframes radar-beam {
    0% {
        transform: translateY(-100%);
    }
    100% {
        transform: translateY(0);
    }
}
@keyframes Heightchange {
    0% {
        height: 0;
    }
    100% {
        height: 100%;
    }
}
</style>

案例二、

vue 扫描二维码、条形码

<template>
    <div class="page-scan">
        <!-- 扫码区域 -->
        <div class="QrCode">
            <video ref="video" height="100%" width="100%" id="video" autoplay></video>
        </div>
        <!-- 扫码样式 -->
        <div class="qr-scanner">
            <div class="box">
                <div class="line"></div>
                <div class="angle"></div>
            </div>
            <div class="back-arrow" @click="clickIndexLeft">
                <span>返回</span>
            </div>
        </div>
    </div>
</template>
  
<script>
// WebRTC适配器 只需要引入就ok
import 'webrtc-adapter'
import { BrowserMultiFormatReader } from '@zxing/library'
export default {
    name: 'scanCodePage',
    data() {
        return {
            codeReader: null
        }
    },
    mounted() {
        this.codeReader = new BrowserMultiFormatReader()
        this.openScan()
    },
    beforeUnmount() {
        this.codeReader && this.codeReader.reset()
    },
    methods: {
        async openScan() {
            this.codeReader
                .listVideoInputDevices()
                .then((videoInputDevices) => {
                    // 默认获取第一个摄像头设备id
                    let firstDeviceId = videoInputDevices[0].deviceId
                    // 获取第一个摄像头设备的名称
                    const videoInputDeviceslablestr = JSON.stringify(
                        videoInputDevices[0].label
                    )
                    if (videoInputDevices.length > 1) {
                        // 判断是否后置摄像头
                        if (videoInputDeviceslablestr.indexOf('back') > -1) {
                            firstDeviceId = videoInputDevices[0].deviceId
                        } else {
                            firstDeviceId = videoInputDevices[1].deviceId
                        }
                    }
                    this.codeReader && this.codeReader.reset() // 重置
                    this.decodeFromInputVideoFunc(firstDeviceId)
                })
                .catch((err) => {
                    console.error(err)
                })
        },
        decodeFromInputVideoFunc(firstDeviceId) {
            this.codeReader.decodeFromInputVideoDeviceContinuously(
                firstDeviceId,
                'video',
                (result, err) => {
                    if (result) {
                        console.log('扫描结果', result)
                        // if (result.text) {
                        //     this.clickIndexLeft(result.text)
                        // }
                    }
                    if (err && !err) {
                        console.error(err)
                    }
                }
            )
        },
        // 停止扫描,并返回上一页
        clickIndexLeft(result) {
            this.codeReader && this.codeReader.reset()
            this.codeReader = null
            // this.$route.params.result = result
            // this.$router.back()
        }
    }
}
</script>
  
<style lang="scss" scope>

.qr-scanner {
    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;
    // width: 100%;
    // height: 100%;
    // position: relative;
    // background-color: #111;

    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 9;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.5);
}
.qr-scanner .box {
    width: 75vw;
    height: 75vw;
    max-height: 75vh;
    max-width: 75vh;
    position: relative;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    overflow: hidden;
    border: 0.1rem solid rgba(0, 255, 51, 0.2);
}
.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;
    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);
    }
}

.qr-scanner .back-arrow {
    position: fixed;
    top: 20px;
    left: 20px;
    width: 30px;
    height: 30px;
    border-radius: 100%;
    background-color: rgba(0, 0, 0, 0.3);
    z-index: 999;

    display: flex;
    justify-content: center;
    align-items: center;
    color: #fff;
}
</style>

想测试的大家可以借助 ‘草料二维码’ 生成二维码测试;

参考文章
https://www.cnblogs.com/memphis-f/p/15543115.html
https://blog.csdn.net/qq_41120902/article/details/116176714

评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值