需求:vue項目要求要在瀏覽器中調用攝像頭進行掃一掃,並識別出二維碼的字符串
插件:QRCodeReader
插件下載
npm install --save vue-qrcode-reader
注意: 需要在https協議下才可以調用相機,實現掃碼。 可以通過配置vue.config.js中的devServer:{https:true}
場景:點擊掃一掃的圖標,觸發掃一掃功能,自動識別出數據之后,enter回車鍵觸發接口請求
在需要用到這個組件的父頁面
template(vue, elementui, pug格式)
el-input(placeholder="手機號/訂單號" v-model="result" class="preview-input" @keyup.enter.native="getOrderinfo()") i(slot="suffix" class="el-icon-full-screen" @click="clickCode()") img(slot="prefix" src="@/assets/img/search.svg" class="input-img" @click="getOrderinfo()") div(class="notes") BarScan(v-bind:scancode="scancode" v-if="scancode" @ok="getResult" )
引入子組件
import BarScan from '../../components/common/scan.vue';
使用到的data
data: () => ({ scancode:false,//控制是否使用掃一掃功能 result: '',//掃碼結果信息 }),
組件注冊
components: { BarScan },
該頁面觸發到的方法
methods: { // 打開相機 clickCode() { this.scancode=true; }, //返回掃描結果並關閉攝像頭 getResult(result){ this.result=result; if(result!==""){ this.scancode=false; } }, //識別完文本之后,enter觸發接口請求 getOrderinfo() } },
掃一掃組件頁面
scan.vue
<template> <div class="scan" v-if="scancode"> <qrcode-stream @decode="onDecode" @init="onInit" style="height: 100vh;"> <div> <div class="qr-scanner"> <div class="box"> <div class="line"></div> <div class="angle"></div> </div> </div> </div> </qrcode-stream> </div> </template> <script> // 下載插件 // cnpm install --save vue-qrcode-reader // 引入 import { QrcodeStream } from 'vue-qrcode-reader' export default { // 注冊 components: { QrcodeStream }, props: { scancode: { type: Boolean, default: false, } }, data() { return { result: '', // 掃碼結果信息 error: '' // 錯誤信息 } }, created(){ this.clickCode() }, methods: { clickCode() { this.scancode=true; }, //回調掃描結果 onDecode (result) { if(result!==""){ this.scancode=false; this.$emit("ok",result) } }, // 檢查是否調用攝像頭 async onInit (promise) { try { await promise } catch (error) { if (error.name === 'NotAllowedError') { this.error = "ERROR: 您需要授予相機訪問權限" } else if (error.name === 'NotFoundError') { this.error = "ERROR: 這個設備上沒有攝像頭" } else if (error.name === 'NotSupportedError') { this.error = "ERROR: 所需的安全上下文(HTTPS、本地主機)" } else if (error.name === 'NotReadableError') { this.error = "ERROR: 相機被占用" } else if (error.name === 'OverconstrainedError') { this.error = "ERROR: 安裝攝像頭不合適" } else if (error.name === 'StreamApiNotSupportedError') { this.error = "ERROR: 此瀏覽器不支持流API" } } }, } } </script> <style scoped> .error { font-weight: bold; color: red; } </style> <style scoped> @import '../../assets/css/scancode.scss'; </style>
引入的css
scancode.scss
.scan{ width: 100vw; border-color: #585858; position: fixed; top: 0; left: 0; } .qrcode-stream-camera{ width: 100%; height: 100%; display: block; -o-object-fit: cover; object-fit: cover; position: absolute; top: 0%; left: 0%; } .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%; */ height: 100vh; position: relative; background-color: #1110; /* background-color: #111; */ } .qr-scanner .box { width: 213px; height: 213px; 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); } }