公司有这个需要本来想CV,找了很久没找到,都是些残文和AI文章。就干脆自己写了一个。
CV就能用,开箱即用兄弟们,觉得好用的点个赞吧兄弟们。
目前只做了移动端的适配哦,用电脑打开是打不开的做了强制限制的。
不罗嗦,上代码
需要安装JSQR去解析二维码
控制台命令: npm install jsqr --save
<template>
<div>
<div v-if="xsyc">
<div ref="videocontainer" v-if="xsycerweima">
<div class="video-container">
<!--video用于显示媒体设备的视频流,自动播放 autoplay-->
<video id="video" autoplay playsinline webkit-playsinline ref="video" ></video>
<!--描绘video截图-->
<canvas id="canvas" style="width: 100%;height: 100%;" v-show="videofalse"></canvas>
<!-- 遮罩层 -->
<div class="wrap" ref="wrap">
<!-- 扫码线 -->
<!-- 直角线 -->
<i class="iconfont icnfontzhijiao1" ></i>
<i class="iconfont icnfontzhijiao2"></i>
<i class="iconfont icnfontzhijiao3"></i>
<i class="iconfont icnfontzhijiao4"></i>
<div class="saomasan">
</div>
</div>
<div ref="shengyupx" class="shengyupx">
<div class="dibubuju">
<i class="iconfont"></i>
<div>
扫描二维码
</div>
</div>
</div>
</div>
</div>
<div v-else>
识别到你的二维码信息是: {{ codedata }}
</div>
</div>
<div v-else>
<div class="PCduan">
扫描二维码暂不支持电脑端,请移步到手机端。
</div>
</div>
</div>
</template>
<script>
import jsQR from 'jsqr'
export default {
name: 'LoginIndex',
data () {
return {
videofales: false,
video: null,
canvas: null,
ctx: null,
xsyc: true,
xsycerweima: true,
codedata: '',
intervalId: null
}
},
components: {
},
created () {
const system = {}
system.pingtai = /(Win32|Win16|WinCE|Mac68K|MacIntel|MacIntel|MacPPC|Linux mips64)/i.test(navigator.platform)
if (system.pingtai) {
// 电脑
console.log('电脑')
this.xsyc = false
} else {
// 手机
console.log('手机')
this.xsyc = true
}
},
mounted () {
// 获取DOM元素
if (this.xsyc) {
this.video = document.getElementById('video')
this.canvas = document.getElementById('canvas')
this.canvas.width = window.innerWidth
this.canvas.height = window.innerHeight
this.ctx = this.canvas.getContext('2d')
console.log(window)
this.scan()
this.intervalId = setInterval(() => {
this.capture()
}, 100)
}
},
methods: {
// 兼容浏览器获取用户媒体方法
// constrains 参数用于指定要使用的摄像头和音频设备。success 和 error 参数用于处理成功和失败的情况。
getUserMedia (constrains, success, error) {
if (navigator.mediaDevices.getUserMedia) {
// 最新标准API
navigator.mediaDevices.getUserMedia(constrains).then(success).catch(error)
} else if (navigator.webkitGetUserMedia) {
// webkit内核浏览器
navigator.webkitGetUserMedia(constrains).then(success).catch(error)
} else if (navigator.mozGetUserMedia) {
// Firefox浏览器
navigator.mozGetUserMedia(constrains).then(success).catch(error)
} else if (navigator.getUserMedia) {
// 旧版API
navigator.getUserMedia(constrains).then(success).catch(error)
}
},
success (stream) {
// 将一个视频流(stream)转换为一个可以被视频元素加载的URL,然后将这个URL设置为视频元素的源。这样,浏览器就可以自动播放这个视频流了。
// 兼容webkit核心浏览器
// 将视频流设置为video元素的源
this.video.srcObject = stream
this.video.play()
},
error (error) {
console.log('访问用户媒体设备失败:' + error.name + ' ' + error.message)
},
// 调用摄像头
scan () {
if (navigator.mediaDevices.getUserMedia || navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia) {
// 调用用户媒体设备,访问摄像头
this.getUserMedia({
audio: false,
video: {
facingMode: 'environment', // user 前置摄像头 environment 后置摄像头
width: { ideal: 1280 },
height: { ideal: 720 },
frameRate: { ideal: 30 },
codec: 'video/mp4;codecs="avc1.42E01E"'
}
}, this.success, this.error)
} else {
alert('你的浏览器不支持访问用户媒体设备')
}
},
// 循环这个动作就可以实现扫码的效果
capture () {
const videoWidth = window.innerWidth
const videoHeight = window.innerHeight
this.ctx.drawImage(this.video, 0, 0, videoWidth, videoHeight)
// 截取高亮部位图片
const cavaswidth = this.canvas.width
const cavasheight = this.canvas.height
const centerX = cavaswidth / 2
const centerY = cavasheight / 2
// 这里是扫描区域的控制 和 this.$refs.wrap.offsetWidth的大小一样 调整wrap的宽度可以调整扫描区域
const desiredSquareSize = this.$refs.wrap.offsetWidth
const squareSize = desiredSquareSize
const x = centerX - squareSize / 2
const y = centerY - squareSize / 2
// 需要识别的二维码部分给jsQR去解析
const imageData = this.ctx.getImageData(x, y, squareSize, squareSize)
const code = jsQR(imageData.data, squareSize, squareSize)
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)
if (code) {
console.log('找到二维码', code.data)
this.codedata = code.data
this.xsycerweima = false
clearInterval(this.intervalId)
this.video.stop()
} else {
console.log('未找到二维码')
}
}
}
}
</script>
<style scoped>
@font-face {
font-family: 'iconfont'; /* Project id 4504064 */
src: url('//at.alicdn.com/t/c/font_4504064_wfyvfsvop7d.woff2?t=1712828573992') format('woff2'),
url('//at.alicdn.com/t/c/font_4504064_wfyvfsvop7d.woff?t=1712828573992') format('woff'),
url('//at.alicdn.com/t/c/font_4504064_wfyvfsvop7d.ttf?t=1712828573992') format('truetype');
}
.iconfont{
font-family:"iconfont" !important;
font-size:25px;font-style:normal;
-webkit-font-smoothing: antialiased;
-webkit-text-stroke-width: 0.2px;
-moz-osx-font-smoothing: grayscale;
}
*{
margin:0px; padding:0px;
overflow: hidden;
}
.video-container {
/* width: 100vw;
height: 100vh; */
overflow: hidden;
}
#video {
/* object-fit: cover; */
/* object-position: center center; */
/* object-position: ; */
/* height: 100%; */
width: 100%;
object-fit: contain;
position: absolute;
overflow: hidden;
}
#canvas {
width: 100vw;
height: 100vh;
}
#capture {
content:'';
position: absolute;
top: 0;
right: 0;
}
.wrap {
content:'';
position: absolute;
width: 70vw;
height: 70vw;
left: 50%;
top: 50%;
transform: translate(-50%,-50%); /*默认居中*/
box-shadow: 0 0 0 999vw rgba(0, 0, 0, .8); /*足够大的投影*/
}
.shengyupx {
position: absolute;
background-color:rgba(44, 40, 40, 1);
bottom: -1vh;
height: 10vh;
width: 100%;
z-index: 999;
overflow: hidden;
}
.dibubuju {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
color: #007bff;
font-size: 2vw;
}
.icnfontzhijiao1 {
content:'';
position: absolute;
left: 0.4vw;
top: -0.4vh;
color: #007bff;
}
.icnfontzhijiao2 {
content:'';
position: absolute;
right: 0.4vw;
top: -0.4vh;
color: #007bff;
}
.icnfontzhijiao3 {
content:'';
position: absolute;
left: 0.4vw;
bottom: -0.7vh;
color: #007bff;
}
.icnfontzhijiao4 {
content:'';
position: absolute;
right: 0.4vw;
bottom: -0.7vh;
color: #007bff;
}
.saomasan {
content:'';
position: absolute;
left: 50%;
top: 0%;
transform: translate(-50%,-50%); /*默认居中*/
height: 3px;
width: 300px;
background: -webkit-linear-gradient(left,rgba(255, 255, 255, 0),#007bff,rgba(255,255,255,0));
background: linear-gradient(to right, rgba(255, 255, 255, 0),#007bff,rgba(255,255,255,0));
animation: moveLine 3s linear infinite;
}
@keyframes moveLine {
0% { transform: translate(-50%,-50%) translateY(-300%); }
50% { transform: translate(-50%,-50%) translateY(10000%); }
100% { transform: translate(-50%,-50%) translateY(-100%); }
}
.PCduan {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
font-size: 4vw;
}
</style>