React H5中实现扫码功能

1,015 阅读2分钟

安装包

npm i @zxing/library

/*
* 1、listVideoInputDevices 
*    获取摄像头设备得到一个摄像头设备数组,根据摄像头的id选择使用的摄像头
* 2、decodeFromInputVideoDeviceContinuously 已不推荐使用-改用decodeFromVideoDevice
*    第一个参数为前面数组得到的摄像头的id,根据传入的摄像头id 选择摄像头扫描 ,id为null 时 默认使用面向环境的摄像头
*/
import React, { useEffect } from 'react'
import { useNavigate } from 'react-router-dom'
import { BrowserMultiFormatReader } from '@zxing/library'
import { recordDetails } from '../../api'
import './index.less'
import { Toast } from 'react-vant'
export default function ScanCode() {
    let num = 0
    let timer
    const navigate = useNavigate()
    const codeReader = new BrowserMultiFormatReader()
    useEffect(() => {
        openScan()
        return () => {
            clearTimeout(timer)
            codeReader.reset()// 组件销毁时重置关闭摄像头
        }
    }, [])

    //调用摄像头
    function openScan() {
        codeReader.listVideoInputDevices().then((videoInputDevices) => {
            // console.log('videoInputDevices', 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
                }
            }

            decodeFromInputVideoFunc(firstDeviceId)
        }).catch(err => { // console.error(err);
        })

    }

    //开始扫码分析
    function decodeFromInputVideoFunc(firstDeviceId) {
        // firstDeviceId  为null 时默认选择面向环境的摄像头
        codeReader.decodeFromVideoDevice(firstDeviceId, 'video',
            async (result, err) => {
                if (result) { 
                /**************扫码成功后做业务逻辑***********/
                }
                if (err) {
                    // console.error(err);
                }
            }
        )
    }


    return (
        <div id='scancode'>
            <main>
                <div className='code'>
                    <div className='hengxian' />
                    <video id="video" style={{ width: '100%' }} />
                    <div className='txt'>请调整扫描角度~</div>
                </div>
            </main>
            <footer>
                <div onClick={() => navigate('/recordlist')} className='cancel'>取消</div>
                <div onClick={() => window.location.reload()}>重新扫描</div>
            </footer>
        </div>
    )
}

自定义扫码样式index.less

#scancode {
    height: 100vh;
    background-color: #F6F7F8;

    main {
        display: flex;
        justify-content: center;
        padding-top: 20px;

        .code {
            width: 250px;
            // height: 150px;
            position: relative;

            .hengxian {
                width: 100%;
                height: 3px;
                background-color: #018FAD;
                opacity: 0.5;
                position: absolute;
                top: -125px;
                animation: 2s 1.5s move linear infinite;
            }

            @keyframes move {
                0% { top: 0px;  }
                100% { top: 250px }
            }
            
            .txt {
                text-align: center;
                color: #21bfdf;
                font-size: 14px;
            }
        }
    }

    footer {
        margin-top: 50px;
        display: flex;
        justify-content: center;

        div {
            width: 120px;
            height: 40px;
            color: white;
            background-color: #018FAD;
            border-radius: 25px;
            display: flex;
            justify-content: center;
            align-items: center;
        }


        .cancel {
            background-color: white;
            color: #018FAD;
            border: 1px solid #018FAD;
            margin-right: 40px;
        }
    }

}