其他分享
首页 > 其他分享> > Vue+zxing实现扫二维码、条形码功能

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

作者:互联网

<script setup >
import { ref, reactive, toRefs } from 'vue'
import { BrowserMultiFormatReader  } from '@zxing/library';
import { Dialog, Notify } from 'vant';
import { useRouter, useRoute } from "vue-router"
const router = useRouter()
const data = reactive({
    loadingShow: false,
    codeReader: null,
    scanText: '',
    vin: null,
    tipMsg: '正在尝试识别....',
    tipShow: false
})
const { loadingShow, codeReader, scanText, vin, tipMsg, tipShow } = toRefs(data);
codeReader.value = new BrowserMultiFormatReader();

openScan();
function openScan() {
    codeReader.value.getVideoInputDevices().then((videoInputDevices) => {
        tipShow.value = true;
        tipMsg.value = '正在调用摄像头...';
        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 => {
        tipShow.value = false;
        console.error(err);
    });
}

function decodeFromInputVideoFunc(firstDeviceId) {
    codeReader.value.reset(); // 重置
    scanText.value = '';
    codeReader.value.decodeFromInputVideoDeviceContinuously(firstDeviceId, 'video', (result, err) => {
        tipMsg.value = '正在尝试识别...';
        scanText.value = '';
        if (result) {
            console.log('扫描结果', result);
            scanText.value = result.text;
            if (scanText.value) {
                tipShow.value = false;
                clickIndexLeft()
                // 这部分接下去的代码根据需要,读者自行编写了
                // this.$store.commit('app/SET_SCANTEXT', result.text);
                // console.log('已扫描的小票列表', this.$store.getters.scanTextArr);
            }
        }
        if (err && !(err)) {
            tipMsg.value = '识别失败';
            setTimeout(() => {
                tipShow.value = false;
            }, 2000)
            console.error(err);
        }
    });
}
function clickIndexLeft(){
  console.log("我要传参了",scanText.value)
   router.replace({
         name:'work',
         params:{
            result:scanText.value
         }
   })
    codeReader.value.reset(); // 重置
}
const onClickRight = () => Toast('按钮');
</script>
<template>
    <div class="page-scan">
        <!--返回-->
        <!-- <van-nav-bar title="扫描二维码/条形码" fixed @click-left="clickIndexLeft()" class="scan-index-bar">
            <template #left>
                <van-icon name="arrow-left" size="18" color="#fff" />
                <span style="color: #fff"> 取消 </span>
            </template>
        </van-nav-bar> -->
        <van-nav-bar
        title="扫描二维码/条形码"
        right-text="按钮"
        left-arrow
         fixed
        @click-right="onClickRight"
         @click-left="clickIndexLeft()"
        />
        <!-- 扫码区域 -->
        <!-- <video ref="video" id="video" class="scan-video" autoplay></video> -->

    <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>{{scanText}}</div>
        <div v-show="tipShow" class="scan-tip"> {{ tipMsg }} </div>
    </div>
</template>
<style scoped lang="scss">

/* .scan-video {
    height: 80vh;
    width: 100%
}

.scan-tip {
    width: 50vw;
    text-align: center;
    margin-bottom: 10vh;
    color: white;
    font-size: 5vw;
}

.page-scan {
    overflow-y: hidden;
    background-color: #363636;
} */



/**
  扫码样式一
*/
.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>

使用的vue3.2 实现的扫码组件封装 样式一

<script setup >
import { ref, reactive, toRefs } from 'vue'
import { BrowserMultiFormatReader  } from '@zxing/library';
import { Dialog, Notify } from 'vant';
import { useRouter, useRoute } from "vue-router"
const router = useRouter()
const data = reactive({
    loadingShow: false,
    codeReader: null,
    scanText: '',
    vin: null,
    tipMsg: '正在尝试识别....',
    tipShow: false
})
const { loadingShow, codeReader, scanText, vin, tipMsg, tipShow } = toRefs(data);
codeReader.value = new BrowserMultiFormatReader();

openScan();
function openScan() {
    codeReader.value.getVideoInputDevices().then((videoInputDevices) => {
        tipShow.value = true;
        tipMsg.value = '正在调用摄像头...';
        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 => {
        tipShow.value = false;
        console.error(err);
    });
}

function decodeFromInputVideoFunc(firstDeviceId) {
    codeReader.value.reset(); // 重置
    scanText.value = '';
    codeReader.value.decodeFromInputVideoDeviceContinuously(firstDeviceId, 'video', (result, err) => {
        tipMsg.value = '正在尝试识别...';
        scanText.value = '';
        if (result) {
            console.log('扫描结果', result);
            scanText.value = result.text;
            if (scanText.value) {
                tipShow.value = false;
                clickIndexLeft()
                // 这部分接下去的代码根据需要,读者自行编写了
                // this.$store.commit('app/SET_SCANTEXT', result.text);
                // console.log('已扫描的小票列表', this.$store.getters.scanTextArr);
            }
        }
        if (err && !(err)) {
            tipMsg.value = '识别失败';
            setTimeout(() => {
                tipShow.value = false;
            }, 2000)
            console.error(err);
        }
    });
}
function clickIndexLeft(){
  console.log("我要传参了",scanText.value)
   router.replace({
         name:'work',
         params:{
            result:scanText.value
         }
   })
    codeReader.value.reset(); // 重置
}
const onClickRight = () => Toast('按钮');
</script>
<template>
    <div class="page-scan">
        <!--返回-->
        <!-- <van-nav-bar title="扫描二维码/条形码" fixed @click-left="clickIndexLeft()" class="scan-index-bar">
            <template #left>
                <van-icon name="arrow-left" size="18" color="#fff" />
                <span style="color: #fff"> 取消 </span>
            </template>
        </van-nav-bar> -->
        <van-nav-bar
        title="扫描二维码/条形码"
        right-text="按钮"
        left-arrow
         fixed
        @click-right="onClickRight"
         @click-left="clickIndexLeft()"
        />
   <!-- 扫码区域 -->
    <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">
        <van-icon name="arrow-left" color="#fff" />
      </div>
    </div>
  </div>


        <!-- 提示语 -->
        <div>{{scanText}}</div>
        <div v-show="tipShow" class="scan-tip"> {{ tipMsg }} </div>
</template>
<style scoped lang="scss">
.QrCode {
  width: 100vw;
  height: 100vh;
  position: relative;
  #video {
    width: 100%;
    height: 100%;
    object-fit: cover;
  }
}


/**
  扫码样式二
*/
.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;
}

</style>

 样式二

 

标签:条形码,Vue,scanner,100%,value,zxing,rgba,height,transparent
来源: https://www.cnblogs.com/ddqyc/p/16658475.html