react h5实现扫一扫功能

/* 
* 
* 1、listVideoInputDevices 
*    获取摄像头设备得到一个摄像头设备数组,根据摄像头的id选择使用的摄像头
* 2、decodeFromInputVideoDeviceContinuously() 
*    第一个参数为前面数组得到的摄像头的id,根据传入的摄像头id 选择摄像头扫描 ,id为null时 默认使用面向环境的摄像头
*/
import React, { useEffect } from 'react'
import { Toast } from 'antd-mobile'
import { BrowserMultiFormatReader } from '@zxing/library'
import "./index.less"
export default function ScanCode (props) {
    const codeReader = new BrowserMultiFormatReader()
    useEffect(() => {
        openScan()
        return (() => {
            destoryScan()
        })
    }, [])

    const destoryScan = () => {
        codeReader.reset();
        codeReader.stopContinuousDecode();
    }

    const openScan = async () => {
        codeReader.listVideoInputDevices().then((videoInputDevices) => {
            console.log(videoInputDevices, 'videoInputDevices');
            // 获取第一个摄像头设备的名称
            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);
        })

    }

    const decodeFromInputVideoFunc = (firstDeviceId) => {
        // firstDeviceId  为null 时默认选择面向环境的摄像头
        codeReader.decodeFromVideoDevice(firstDeviceId, 'video', (result, err) => {
            if (result) {
                Toast.show({
                    content: "扫描成功"
                })
                props.getResult(result.text)
                destoryScan()
            }
            if (err) {
                // console.error(err);
            }
        })
    }

    const backScan = () => {
        props.getResult('返回')
        destoryScan()
    }
    return (
        <div className="page-scan">
            <div className='back' onClick={backScan}><img src={require("../../assets/img/arrow_back.png").default} alt="" /> 返回</div>
            <div className="scan-box">
                <video id="video" className="scan-video" autoplay></video>
                <div className="qr-scanner">
                    <div className="box">
                        <div className="line"></div>
                        <div className="angle"></div>
                    </div>
                </div>
                <div className="scan-tip">扫描条形码</div>
            </div>
        </div>
    )
}

 

./index.less文件
.scan-box {
    position: fixed;
    top: 0;
    left: 0;
    height: 100%;
    width: 100vw;
    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;
  }
  .back{
    font-size: 24px;
    color: #fff;
    font-weight: bolder;
    line-height: 50px;
    display: flex;
    align-items: center;
    z-index: 9999;
    position: fixed;
    top: 30px;
    left: 20px;
    img{
        width: 40px;
        height: 40px;
    }
  }
  
  .scan-video {
    height: 100vh;
    width: 100vw;
    object-fit: cover;
  }
  
  .qr-scanner .box {
    width: 500px;
    height: 500px;
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    overflow: hidden;
    border: 0.1rem solid rgba(0, 255, 51, 0.2);
    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);
    }
  }
  
  .scan-tip {
    width: 100vw;
    text-align: center;
    margin-bottom: 5vh;
    color: white;
    font-size: 5vw;
    position: absolute;
    bottom: 50px;
    left: 0;
    color: #fff;
  }
  
  .page-scan {
    overflow-y: hidden;
    z-index: 999;
  }

 

posted @ 2023-05-26 15:33  自_定义  阅读(117)  评论(1编辑  收藏  举报