本文实例为大家分享了vue2实现手势密码功能的具体代码,供大家参考,具体内容如下
组件:
<template>
<div class="masks" v-show="currentValue">
<div class="gesturePwd">
<div class="box">
<h4 ref="gestureTitle" class="gestureTitle">请绘制您的图形密码</h4>
<a class="reset" ref="updatePassword" @click="updatePassword()">重置密码</a>
<a class="close" ref="updatePassword" @click="closePwd(false)">关闭</a>
<canvas ref="canvas"></canvas>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
value: {
type: Boolean,
default: false
},
},
data() {
return {
currentValue: false,
ctx: '',
width: 0,
height: 0,
devicePixelRatio: 0,
chooseType: '',
r: '',// 公式计算
lastPoint: [],
arr: [],
restPoint: [],
pswObj: {step: 2},
canvas: ''
}
},
watch: {
value: {
handler: function (val) {
this.currentValue = val
},
immediate: true
},
currentValue(val) {
this.$emit(val ? 'on-show' : 'on-hide')
this.$emit('input', val)
}
},
created() {
if (typeof this.value !== 'undefined') {
this.currentValue = this.value
}
},
mounted() {
this.setChooseType(3);
},
methods: {
closePwd(bol) {
this.$emit("handPwd",bol);
this.currentValue = false;
},
drawCle(x, y) { // 初始化解锁密码面板 小圆圈
this.ctx.strokeStyle = '#87888a';//密码的点点默认的颜色
this.ctx.lineWidth = 2;
this.ctx.beginPath();
this.ctx.arc(x, y, this.r, 0, Math.PI * 2, true);
this.ctx.closePath();
this.ctx.stroke();
},
drawPoint(style) { // 初始化圆心
for (var i = 0; i < this.lastPoint.length; i++) {
this.ctx.fillStyle = style;
this.ctx.beginPath();
this.ctx.arc(this.lastPoint[i].x, this.lastPoint[i].y, this.r / 2.5, 0, Math.PI * 2, true);
this.ctx.closePath();
this.ctx.fill();
}
},
drawStatusPoint(type) { // 初始化状态线条
for (var i = 0; i < this.lastPoint.length; i++) {
this.ctx.strokeStyle = type;
this.ctx.beginPath();
this.ctx.arc(this.lastPoint[i].x, this.lastPoint[i].y, this.r, 0, Math.PI * 2, true);
this.ctx.closePath();
this.ctx.stroke();
}
},
drawLine(style, po, lastPoint) {//style:颜色 解锁轨迹
this.ctx.beginPath();
this.ctx.strokeStyle = style;
this.ctx.lineWidth = 3;
this.ctx.moveTo(this.lastPoint[0].x, this.lastPoint[0].y);
for (var i = 1; i < this.lastPoint.length; i++) {
this.ctx.lineTo(this.lastPoint[i].x, this.lastPoint[i].y);
}
this.ctx.lineTo(po.x, po.y);
this.ctx.stroke();
this.ctx.closePath();
},
createCircle() {// 创建解锁点的坐标,根据canvas的大小来平均分配半径
var n = this.chooseType;
var count = 0;
this.r = this.ctx.canvas.width / (2 + 4 * n);// 公式计算
this.lastPoint = [];
this.arr = [];
this.restPoint = [];
var r = this.r;
for (var i = 0; i < n; i++) {
for (var j = 0; j < n; j++) {
count++;
var obj = {
x: j * 4 * r + 3 * r,
y: i * 4 * r + 3 * r,
index: count
};
this.arr.push(obj);
this.restPoint.push(obj);
}
}
this.ctx.clearRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height);
for (var i = 0; i < this.arr.length; i++) {
this.drawCle(this.arr[i].x, this.arr[i].y);
}
},
getPosition(e) {// 获取touch点相对于canvas的坐标
var rect = e.currentTarget.getBoundingClientRect();
var po = {
x: (e.touches[0].clientX - rect.left) * this.devicePixelRatio,
y: (e.touches[0].clientY - rect.top) * this.devicePixelRatio
};
return po;
},
update(po) {// 核心变换方法在touchmove时候调用
this.ctx.clearRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height);
for (var i = 0; i < this.arr.length; i++) { // 每帧先把面板画出来
this.drawCle(this.arr[i].x, this.arr[i].y);
}
this.drawPoint('#27AED5');// 每帧花轨迹
this.drawStatusPoint('#27AED5');// 每帧花轨迹
this.drawLine('#27AED5', po, this.lastPoint);// 每帧画圆心
for (var i = 0; i < this.restPoint.length; i++) {
if (Math.abs(po.x - this.restPoint[i].x) < this.r && Math.abs(po.y - this.restPoint[i].y) < this.r) {
this.drawPoint(this.restPoint[i].x, this.restPoint[i].y);
this.lastPoint.push(this.restPoint[i]);
this.restPoint.splice(i, 1);
break;
}
}
},
checkPass(psw1, psw2) {// 检测密码
var p1 = '', p2 = '';
for (var i = 0; i < psw1.length; i++) {
p1 += psw1[i].index + psw1[i].index;
}
for (var i = 0; i < psw2.length; i++) {
p2 += psw2[i].index + psw2[i].index;
}
return p1 === p2;
},
storePass(psw) {// touchend结束之后对密码和状态的处理
if (this.pswObj.step == 1) {
if (this.checkPass(this.pswObj.fpassword, psw)) {
this.pswObj.step = 2;
this.pswObj.spassword = psw;
this.$refs.gestureTitle.innerHTML = '密码保存成功';
this.drawStatusPoint('#2CFF26');
this.drawPoint('#2CFF26');
window.localStorage.setItem('passwordxx', JSON.stringify(this.pswObj.spassword));
window.localStorage.setItem('chooseType', this.chooseType);
} else {
this.$refs.gestureTitle.innerHTML = '两次不一致,重新输入';
this.drawStatusPoint('red');
this.drawPoint('red');
delete this.pswObj.step;
}
} else if (this.pswObj.step == 2) {
if (this.checkPass(this.pswObj.spassword, psw)) {
var gestureTitle = this.$refs.gestureTitle;
gestureTitle.style.color = "#2CFF26";
gestureTitle.innerHTML = '解锁成功';
this.drawStatusPoint('#2CFF26');//小点点外圈高亮
this.drawPoint('#2CFF26');
this.drawLine('#2CFF26', this.lastPoint[this.lastPoint.length - 1], this.lastPoint);// 每帧画圆心
this.closePwd(true);
} else if (psw.length < 4) {
this.drawStatusPoint('red');
this.drawPoint('red');
this.drawLine('red', this.lastPoint[this.lastPoint.length - 1], this.lastPoint);// 每帧画圆心
var gestureTitle = this.$refs.gestureTitle;
gestureTitle.style.color = "red";
gestureTitle.innerHTML = '请连接4个点';
} else {
this.drawStatusPoint('red');
this.drawPoint('red');
this.drawLine('red', this.lastPoint[this.lastPoint.length - 1], this.lastPoint);// 每帧画圆心
var gestureTitle = this.$refs.gestureTitle;
gestureTitle.style.color = "red";
gestureTitle.innerHTML = '密码错误';
}
} else {
this.pswObj.step = 1;
this.pswObj.fpassword = psw;
this.$refs.gestureTitle.innerHTML = '再次输入';
}
},
makeState() {
if (this.pswObj.step == 2) {
this.$refs.updatePassword.style.display = 'block';
var gestureTitle = this.$refs.gestureTitle;
gestureTitle.style.color = "#87888a";
gestureTitle.innerHTML = '请解锁';
} else if (this.pswObj.step == 1) {
this.$refs.updatePassword.style.display = 'none';
} else {
this.$refs.updatePassword.style.display = 'block';
}
},
setChooseType(type) {
this.chooseType = type;
this.init();
},
updatePassword() {
window.localStorage.removeItem('passwordxx');
window.localStorage.removeItem('chooseType');
this.pswObj = {};
this.$refs.gestureTitle.innerHTML = '绘制解锁图案';
this.reset();
},
initDom() {
this.chooseType = Number(window.localStorage.getItem('chooseType')) || 3;
this.devicePixelRatio = window.devicePixelRatio || 1;
var canvas = this.$refs.canvas;
var width = this.width || 320;
var height = this.height || 320;
// 高清屏锁放
canvas.style.width = width + "px";
canvas.style.height = height + "px";
canvas.height = height * this.devicePixelRatio;
canvas.width = width * this.devicePixelRatio;
},
init() {
this.initDom();
this.pswObj = window.localStorage.getItem('passwordxx') ? {
step: 2,
spassword: JSON.parse(window.localStorage.getItem('passwordxx'))
} : {};
this.lastPoint = [];
this.makeState();
this.touchFlag = false;
this.canvas = this.$refs.canvas;
this.ctx = this.canvas.getContext('2d');
this.createCircle();
this.bindEvent();
},
reset() {
this.makeState();
this.createCircle();
},
bindEvent() {
var self = this;
this.canvas = this.$refs.canvas;
this.canvas.addEventListener("touchstart", function (e) {
e.preventDefault();// 某些android 的 touchmove不宜触发 所以增加此行代码
var po = self.getPosition(e);
for (var i = 0; i < self.arr.length; i++) {
if (Math.abs(po.x - self.arr[i].x) < self.r && Math.abs(po.y - self.arr[i].y) < self.r) {
self.touchFlag = true;
self.drawPoint(self.arr[i].x, self.arr[i].y);
self.lastPoint.push(self.arr[i]);
self.restPoint.splice(i, 1);
break;
}
}
}, false);
this.canvas.addEventListener("touchmove", function (e) {
if (self.touchFlag) {
self.update(self.getPosition(e));
}
}, false);
this.canvas.addEventListener("touchend", function (e) {
if (self.touchFlag) {
self.touchFlag = false;
self.storePass(self.lastPoint);
setTimeout(function () {
self.reset();
}, 1000);
}
}, false);
}
}
}
</script>
<style scoped>
.masks {
text-align: center;
position: fixed;
z-index: 1000;
top: 0;
right: 0;
left: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.6);
}
.gesturePwd {
position: fixed;
z-index: 5000;
width: 100%;
height: 100%;
top: 50%;
left: 50%;
-webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
text-align: center;
border-radius: 3px;
overflow: hidden;
background-color: #000;
}
.gestureTitle {
color: #87888a;
margin-top: 85px;
font-size: 20px;
font-weight: normal;
}
.box{
position: absolute;
top:0;
left:0;
right:0;
bottom:0;
}
.box a{
position: absolute;
top: 5px;
color:#fff;
font-size: 13px;
display:block;
}
a.reset{
left: 5px;
}
a.close{
right :5px;
}
.box canvas{
background-color: #000;
display: inline-block;
margin-top: 76px;
width: 320px;
height: 320px;
}
</style>
调用:
<template>
<div class="hello">
<button @click="showClicked" style="width:90px;height:50px;font-size:16px;background-color:#eee">手势密码</button>
<pwd v-model="showPwd" @handPwd="handPwd"></pwd>
</div>
</template>
<script>
import pwd from '@/components/pwd'
export default {
name: 'hello',
data() {
return {
showPwd: false
}
},
methods: {
showClicked() {
this.showPwd = true;
},
handPwd(val) {
console.log(val);
}
},
components: {
pwd
},
}
</script>