258 lines
7.2 KiB
Vue
258 lines
7.2 KiB
Vue
<template>
|
|
<view class="sliderBox">
|
|
<view class="content">
|
|
<view class="headbox">
|
|
<text class="text">请完成安全验证</text>
|
|
<view class="tf-close" @click.stop="close_"><up-icon name="close" /></view>
|
|
</view>
|
|
<canvas :style="{ width: canvasW + 'px', height: canvasH + 'px' }" class="canvasBox" canvas-id="mycanvas" id="mycanvas"></canvas>
|
|
<movable-area class="moveArea">
|
|
<view class="text">滑动滑块完成拼图</view>
|
|
<movable-view class="moveView" direction="all" :x="canvasX2" @change="changePath" @touchend="endTouch" @mouseup="endTouch">
|
|
<view class="moveBox"></view>
|
|
</movable-view>
|
|
</movable-area>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script>
|
|
export default {
|
|
props:{
|
|
verifyImgs:{
|
|
type:Array,
|
|
default: function(){
|
|
return []
|
|
}
|
|
}
|
|
},
|
|
data() {
|
|
return {
|
|
verifyIndex: 0,
|
|
canvasW: '',
|
|
canvasH: '',
|
|
canvasX2: 0,
|
|
canvasX: 0,
|
|
ctx: null,
|
|
jgX: 0,
|
|
dqImgPath:'',
|
|
Color: uni.getStorageSync('theme_color')
|
|
}
|
|
},
|
|
created() {
|
|
this.canvasW = uni.upx2px(580)
|
|
this.canvasH = uni.upx2px(290)
|
|
},
|
|
mounted() {
|
|
this.$nextTick(()=>{
|
|
this.init()
|
|
})
|
|
},
|
|
methods: {
|
|
// 生成从minNum到maxNum的随机数
|
|
randomNum(minNum,maxNum){
|
|
switch(arguments.length){
|
|
case 1:
|
|
return parseInt(Math.random() * minNum + 1, 10);
|
|
break;
|
|
case 2:
|
|
return parseInt(Math.random()*(maxNum-minNum+1)+minNum,10);
|
|
break;
|
|
default:
|
|
return 0;
|
|
break;
|
|
}
|
|
},
|
|
close_(){
|
|
this.$emit('close')
|
|
},
|
|
async init(){
|
|
if(this.verifyImgs.length == 0){
|
|
uni.showToast({
|
|
title: '背景图不能为空',
|
|
icon: 'none'
|
|
})
|
|
return
|
|
}
|
|
this.canvasX2--
|
|
this.canvasX = 0
|
|
this.verifyIndex = this.randomNum(0, this.verifyImgs.length - 1)
|
|
this.ctx = uni.createCanvasContext('mycanvas', this)
|
|
this.jgX = this.randomNum(uni.upx2px(150),uni.upx2px(450))
|
|
this.dqImgPath = await this.parseImagePath(this.verifyImgs[this.verifyIndex].src)
|
|
this.huatu()
|
|
},
|
|
endTouch(){
|
|
if(Math.abs(this.canvasX - this.jgX) <= 5){
|
|
this.$emit('succeed')
|
|
}else{
|
|
uni.showToast({
|
|
title: '验证失败',
|
|
icon:"error"
|
|
});
|
|
this.init()
|
|
}
|
|
},
|
|
huatu(){
|
|
let this_ = this
|
|
let r = uni.upx2px(10)
|
|
let XX = this.canvasX
|
|
let YY = uni.upx2px(100)
|
|
let cs = uni.upx2px(20)
|
|
this_.ctx.drawImage(this_.dqImgPath, 0, 0, this_.canvasW, this_.canvasH)
|
|
|
|
//画不可移动的拼图块
|
|
this_.ctx.beginPath()
|
|
this_.ctx.moveTo(-2*r+this_.jgX+cs+2*r, YY-2*r+2*r)
|
|
this_.ctx.lineTo(-2*r+this_.jgX+cs+5.5*r, YY-2*r+2*r)
|
|
this_.ctx.arcTo(-2*r+this_.jgX+cs+5.5*r, YY-2*r+3*r, XX-2+this_.jgX*r+cs+6.5*r, YY-2*r+3*r, r)
|
|
this_.ctx.lineTo(-2*r+this_.jgX+cs+7.5*r, YY-2*r+3*r)
|
|
this_.ctx.arcTo(-2*r+this_.jgX+cs+8.5*r, YY-2*r+3*r, -2*r+this_.jgX+cs+8.5*r, YY-2*r+2*r, r)
|
|
this_.ctx.lineTo(-2*r+this_.jgX+cs+12*r, YY-2*r+2*r)
|
|
this_.ctx.lineTo(-2*r+this_.jgX+cs+12*r, YY-2*r+11*r)
|
|
this_.ctx.lineTo(-2*r+this_.jgX+cs+8.5*r, YY-2*r+11*r)
|
|
this_.ctx.arcTo(-2*r+this_.jgX+cs+8.5*r, YY-2*r+12*r, -2*r+this_.jgX+cs+7.5*r, YY-2*r+12*r, r)
|
|
this_.ctx.lineTo(-2*r+this_.jgX+cs+6.5*r, YY-2*r+12*r)
|
|
this_.ctx.arcTo(-2*r+this_.jgX+cs+5.5*r, YY-2*r+12*r, -2*r+this_.jgX+cs+5.5*r, YY-2*r+11*r, r)
|
|
this_.ctx.lineTo(-2*r+this_.jgX+cs+2*r, YY-2*r+11*r)
|
|
this_.ctx.lineTo(-2*r+this_.jgX+cs+2*r, YY-2*r+8*r)
|
|
this_.ctx.arcTo(-2*r+this_.jgX+cs+3*r, YY-2*r+8*r, -2*r+this_.jgX+cs+3*r, YY-2*r+7*r, r)
|
|
this_.ctx.lineTo(-2*r+this_.jgX+cs+3*r, YY-2*r+6*r)
|
|
this_.ctx.arcTo(-2*r+this_.jgX+cs+3*r, YY-2*r+5*r, -2*r+this_.jgX+cs+2*r, YY-2*r+5*r, r)
|
|
this_.ctx.lineTo(-2*r+this_.jgX+cs+2*r, YY-2*r+2*r)
|
|
this_.ctx.shadowBlur = 10
|
|
this_.ctx.shadowColor="#ffffff"
|
|
this_.ctx.fillStyle = "rgba(0,0,0,0.5)"
|
|
this_.ctx.fill()
|
|
this_.ctx.restore()
|
|
//画可移动的拼图块
|
|
this_.ctx.beginPath()
|
|
this_.ctx.save()
|
|
this_.ctx.moveTo(XX-2*r+cs+2*r, YY-2*r+2*r)
|
|
this_.ctx.lineTo(XX-2*r+cs+5.5*r, YY-2*r+2*r)
|
|
this_.ctx.arcTo(XX-2*r+cs+5.5*r, YY-2*r+3*r, XX-2*r+cs+6.5*r, YY-2*r+3*r, r)
|
|
this_.ctx.lineTo(XX-2*r+cs+7.5*r, YY-2*r+3*r)
|
|
this_.ctx.arcTo(XX-2*r+cs+8.5*r, YY-2*r+3*r, XX-2*r+cs+8.5*r, YY-2*r+2*r, r)
|
|
this_.ctx.lineTo(XX-2*r+cs+12*r, YY-2*r+2*r)
|
|
this_.ctx.lineTo(XX-2*r+cs+12*r, YY-2*r+11*r)
|
|
this_.ctx.lineTo(XX-2*r+cs+8.5*r, YY-2*r+11*r)
|
|
this_.ctx.arcTo(XX-2*r+cs+8.5*r, YY-2*r+12*r, XX-2*r+cs+7.5*r, YY-2*r+12*r, r)
|
|
this_.ctx.lineTo(XX-2*r+cs+6.5*r, YY-2*r+12*r)
|
|
this_.ctx.arcTo(XX-2*r+cs+5.5*r, YY-2*r+12*r, XX-2*r+cs+5.5*r, YY-2*r+11*r, r)
|
|
this_.ctx.lineTo(XX-2*r+cs+2*r, YY-2*r+11*r)
|
|
this_.ctx.lineTo(XX-2*r+cs+2*r, YY-2*r+8*r)
|
|
this_.ctx.arcTo(XX-2*r+cs+3*r, YY-2*r+8*r, XX-2*r+cs+3*r, YY-2*r+7*r, r)
|
|
this_.ctx.lineTo(XX-2*r+cs+3*r, YY-2*r+6*r)
|
|
this_.ctx.arcTo(XX-2*r+cs+3*r, YY-2*r+5*r, XX-2*r+cs+2*r, YY-2*r+5*r, r)
|
|
this_.ctx.lineTo(XX-2*r+cs+2*r, YY-2*r+2*r)
|
|
this_.ctx.shadowBlur = 10
|
|
this_.ctx.shadowColor = '#ffffff'
|
|
this_.ctx.fill()
|
|
this_.ctx.clip()
|
|
this_.ctx.drawImage(this_.dqImgPath, this_.canvasX - this_.jgX, 0, this_.canvasW, this_.canvasH)
|
|
this_.ctx.restore()
|
|
//绘图
|
|
this_.ctx.draw()
|
|
},
|
|
changePath(e) {
|
|
this.canvasX = e.detail.x
|
|
this.huatu()
|
|
},
|
|
async parseImagePath(imgSrc) {
|
|
return new Promise((resolve, reject) => {
|
|
uni.getImageInfo({
|
|
src: imgSrc,
|
|
success: function(image) {
|
|
resolve(image.path)
|
|
},
|
|
fail(err) {
|
|
reject()
|
|
}
|
|
})
|
|
})
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style lang="less">
|
|
.sliderBox{
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
bottom: 0;
|
|
right: 0;
|
|
z-index: 100;
|
|
background-color: rgba(0,0,0,.3);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
.content{
|
|
width: 640upx;
|
|
height: 584upx;
|
|
background-color: #fff;
|
|
border-radius: 6upx;
|
|
box-shadow: 0 0 50upx 0upx rgba(0, 0, 0, 0.2);
|
|
.headbox{
|
|
height: 100upx;
|
|
line-height: 100upx;
|
|
padding: 0 32upx;
|
|
border-bottom: 1px solid #E1E3E9;
|
|
flex-direction: row;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
.text{
|
|
font-size: 32upx;
|
|
flex: 1;
|
|
}
|
|
}
|
|
.canvasBox{
|
|
margin: 30rpx auto;
|
|
align-self: center;
|
|
}
|
|
.moveArea{
|
|
margin: 30rpx auto;
|
|
align-self: center;
|
|
width: 580upx;
|
|
height: 75upx;
|
|
line-height: 75upx;
|
|
text-align: center;
|
|
font-size: 28upx;
|
|
border-radius: 6upx;
|
|
border: 1px solid #E1E3E9;
|
|
background-color: #F7F8F9;
|
|
overflow: hidden;
|
|
position: relative;
|
|
.text{
|
|
width: 100%;
|
|
height: 75upx;
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
color: #424649;
|
|
text-align: center;
|
|
}
|
|
.moveView{
|
|
height: 75upx;
|
|
width: 75upx;
|
|
background-color: #fff;
|
|
box-shadow: 0 0 10upx 0upx rgba(0, 0, 0, 0.2);
|
|
background-image: url(img/tf-arrows.png);
|
|
background-size: 34upx;
|
|
background-position: center;
|
|
background-repeat: no-repeat;
|
|
.moveBox{
|
|
position: absolute;
|
|
background-color: v-bind('Color');
|
|
top: 0;
|
|
left: -580upx;
|
|
width: 580upx;
|
|
height: 100%;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</style>
|