You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
139 lines
3.4 KiB
139 lines
3.4 KiB
1 year ago
|
<template>
|
||
|
<view class="gesture-lock" :class="{error:error}" :style="{width: containerWidth +'rpx', height:containerWidth +'rpx'}"
|
||
|
@touchstart.stop="onTouchStart" @touchmove.stop="onTouchMove" @touchend.stop="onTouchEnd">
|
||
|
<!-- 同级 v-for 的 key 重复会有问题,需要套一层。 -->
|
||
|
<!-- 9 个圆 -->
|
||
|
<view>
|
||
|
<view v-for="(item,i) in circleArray" :key="i" class="cycle" :class="{check:item.check}" :style="{left:item.style.left,top:item.style.top,width:item.style.width,height:item.style.width}">
|
||
|
</view>
|
||
|
</view>
|
||
|
<view>
|
||
|
<!-- 已激活锁之间的线段 -->
|
||
|
<view v-for="(item,i) in lineArray" :key="i" class="line" :style="{left:item.activeLeft,top:item.activeTop,width:item.activeWidth,'-webkit-transform':'rotate('+item.activeRotate+')',transform:'rotate('+item.activeRotate+')'}">
|
||
|
</view>
|
||
|
</view>
|
||
|
<!-- 最后一个激活的锁与当前位置之间的线段 -->
|
||
|
<view class="line" :style="{left:activeLine.activeLeft,top:activeLine.activeTop,width:activeLine.activeWidth,'-webkit-transform':'rotate('+activeLine.activeRotate+')',transform:'rotate('+activeLine.activeRotate+')'}">
|
||
|
</view>
|
||
|
</view>
|
||
|
</template>
|
||
|
<script>
|
||
|
import GestureLock from './gestureLock';
|
||
|
|
||
|
export default {
|
||
|
name: 'index',
|
||
|
props: {
|
||
|
/**
|
||
|
* 容器宽度
|
||
|
*/
|
||
|
containerWidth: {
|
||
|
type: [Number, String],
|
||
|
default: 0
|
||
|
},
|
||
|
/**
|
||
|
* 圆的半径
|
||
|
*/
|
||
|
cycleRadius: {
|
||
|
type: [Number, String],
|
||
|
default: 0
|
||
|
},
|
||
|
/**
|
||
|
* 已设定的密码
|
||
|
*/
|
||
|
password: {
|
||
|
type: Array,
|
||
|
default () {
|
||
|
return []
|
||
|
}
|
||
|
},
|
||
|
},
|
||
|
data() {
|
||
|
return {
|
||
|
gestureLock: {}, // 锁对象
|
||
|
circleArray: [], // 圆对象数组
|
||
|
lineArray: [], // 已激活锁之间的线段
|
||
|
activeLine: {}, // 最后一个激活的锁与当前位置之间的线段
|
||
|
error: false
|
||
|
}
|
||
|
},
|
||
|
methods: {
|
||
|
onTouchStart(e) {
|
||
|
this.gestureLock.onTouchStart(e);
|
||
|
this.refesh();
|
||
|
},
|
||
|
|
||
|
onTouchMove(e) {
|
||
|
this.gestureLock.onTouchMove(e);
|
||
|
this.refesh();
|
||
|
},
|
||
|
|
||
|
onTouchEnd(e) {
|
||
|
const checkPoints = this.gestureLock.onTouchEnd(e);
|
||
|
if (!this.password.length || checkPoints.join('') == this.password.join('')) {
|
||
|
this.refesh();
|
||
|
this.$emit('end', checkPoints);
|
||
|
} else {
|
||
|
this.error = true;
|
||
|
setTimeout(() => {
|
||
|
this.refesh();
|
||
|
this.$emit('end', checkPoints);
|
||
|
}, 800);
|
||
|
}
|
||
|
|
||
|
},
|
||
|
refesh() {
|
||
|
this.error = false;
|
||
|
this.circleArray = this.gestureLock.getCycleArray();
|
||
|
this.lineArray = this.gestureLock.getLineArray();
|
||
|
this.activeLine = this.gestureLock.getActiveLine();
|
||
|
}
|
||
|
},
|
||
|
mounted() {
|
||
|
this.gestureLock = new GestureLock(this.containerWidth, this.cycleRadius);
|
||
|
this.refesh();
|
||
|
}
|
||
|
}
|
||
|
</script>
|
||
|
|
||
|
<style scoped>
|
||
|
.gesture-lock {
|
||
|
margin: 0 auto;
|
||
|
position: relative;
|
||
|
box-sizing: border-box;
|
||
|
overflow: auto;
|
||
|
}
|
||
|
|
||
|
.gesture-lock .cycle {
|
||
|
box-sizing: border-box;
|
||
|
position: absolute;
|
||
|
border: 2px solid #66aaff;
|
||
|
border-radius: 50%;
|
||
|
}
|
||
|
|
||
|
.gesture-lock .cycle.check:after {
|
||
|
content: "";
|
||
|
display: block;
|
||
|
position: absolute;
|
||
|
width: 32%;
|
||
|
height: 32%;
|
||
|
border: 2px solid #66aaff;
|
||
|
border-radius: 50%;
|
||
|
top: 50%;
|
||
|
left: 50%;
|
||
|
transform: translate(-50%, -50%);
|
||
|
}
|
||
|
|
||
|
.gesture-lock .line {
|
||
|
height: 0;
|
||
|
border-top: 2px solid #66aaff;
|
||
|
position: absolute;
|
||
|
transform-origin: left center;
|
||
|
}
|
||
|
|
||
|
.gesture-lock.error .cycle.check,
|
||
|
.gesture-lock.error .cycle.check:after,
|
||
|
.gesture-lock.error .line {
|
||
|
border-color: #ffa197;
|
||
|
}
|
||
|
</style>
|