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

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

时间:2022-09-05 16:01:33浏览次数:62  
标签:条形码 Vue scanner 100% value zxing rgba height transparent

<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
From: https://www.cnblogs.com/ddqyc/p/16658475.html

相关文章

  • vue3 组件-表格分页
    typescript类型提示(属性、方法、el-table与el-pagination自带ts类型)json配置el-table控制栏自定义单元格编辑编辑行自动请求接口接口请求参数与响应数据路径......
  • vue3 组件-开始结束日期选择器
    https://kuangyx.cn/docs/文章/vue3组件/时间选择.html......
  • vue3 组件-上升下降趋势标记
    https://kuangyx.cn/docs/文章/vue3组件/趋势标记.html......
  • vue3 组件-省市区城市选择器
    查看文档......
  • vue中使用Moment日期格式化
    vue中使用Moment日期格式化moment.js是一个JavaScript日期处理类库。由于用antdesign日期组件取得的值是moment类型,而往数据库中保存需要的是字符串类型.这里就用到了m......
  • 关于vuex的个人理解
    Vuex数据状态持久化的插件(vuex-persistedstate--save)在store项目下的index,js使用 importcreatePersistedStatefrom"vuex-persistedstate"1.store:{}存储变量,(vue......
  • vue3——readonly 与 shallowReadonly
    readonly:让一个响应式数据变为只读的(深只读)。shallowReadonly:让一个响应式数据变为只读的(浅只读,只读第一层)。isReadonly:判断一个数据是不是只读数据应用场景:......
  • 063_末晨曦Vue技术_过渡 & 动画之显性的过渡持续时间
    显性的过渡持续时间点击打开视频讲解更加详细在很多情况下,Vue可以自动得出过渡效果的完成时机。默认情况下,Vue会等待其在过渡效果的根元素的第一个transitionend或a......
  • vue项目里地图组件截图快照的实现方法---html2Canvas
    一、前言最近项目里要求要把当前地图截图展示在小窗里,之前没接触这种请求,于是我就百度了一下,发现有这么一块插件html2Canvas,它能够将dom元素转换成canvas进行截图保存,而......
  • vue+websocket
    一、websocket是什么WebSocket通信协议于2011年被IETF定为标准RFC6455,并由RFC7936补充规范。WebSocketAPI也被[W3C]定为标准。它算是html5规范中的一个部分,算是一种协......