一、应用介绍
十五年前,乔布斯老爷子发布了跨时代的作品:iphone 4
。当他演示用手滑动给手机解锁的操作时,整个世界都沸腾了!
的确,实时说明,在滑动解锁手机出来之后,全世界都陷入于对该形式的狂热追求中。
那么,现在小程序成为了新的时代宠儿。各家的小程序平台百花齐放,一个个厂商的小程序平台就好比一个个的新的操作系统。
续iphone滑动解锁之后,由安卓手机引领的九宫格密码锁也成为了时代的潮流。
那么这次我们来尝试一下,如何在小程序的系统里面,摆脱普通的密码登录授权,也加入并体验到九宫格密码解锁的功能特效!
二、效果展示
三、技术与难点
3.1 基本开发环境
- 开发框架:
uniapp
- 代码语法:
vue 2
、html
、css3
3.2 开发要点
3.2.1 引入九宫格插件
为了更高效的开发出手势登录的效果,我们这里直接引入了第三方的九宫格插件:mpvueGestureLock
3.2.2 自适应手机屏幕比
当用户绘制手势秘密的时候,我们需要保证九宫格每个格点的位置和形状不会有大的畸变,这会严重影响用户的手势输入体验,所以我们在加载界面功能之前需要使得九宫格动态适应屏幕的屏占比。
/* 测量屏幕高度,固定手势锁位置 */ getScreenHeight() { //测量屏幕宽度(得到的是px单位) const deviceInfo = uni.getSystemInfoSync(); console.log("设备信息:" + JSON.stringify(deviceInfo)); this.screenWidth = deviceInfo.screenWidth; console.log("屏幕宽高:(" + this.screenWidth + ";" + this.screenHeight + ")"); },
3.2.3 手势注册逻辑
- 手势的注册逻辑一般有两步,第一步用于输入,第二步用于与之前的输入进行校验
/* 注册、修改-第一次绘制手势 */ firstDraw() { if (this.lockType == 1) { console.log("注册-绘制第一次"); } else if (this.lockType == 3) { console.log("修改密码-重新设置第一次"); } if (this.password.length < 4) { this.text = '至少连接4个点,请重新绘制'; this.password = []; } else { this.text = '再次绘制图案进行确认'; this.showLockConfirm = true; } }, /* 注册、修改-第二次绘制手势 */ secondDraw(pwdAgain) { if (this.lockType == 1) { console.log("注册-绘制第二次"); } else if (this.lockType == 3) { console.log("修改密码-重新设置第二次"); } if (this.password.join('') === pwdAgain.join('')) { this.text = '手势设定完成,点击确认完成设定'; this.confirmEnable = true; console.log("密码:" + JSON.stringify(this.password)); // this.password = [] } else { this.text = '两次手势设定不一致' this.confirmEnable = false; this.password = [] } },
3.2.4 手势登录逻辑
- 绑定插件的
@end=onEnd()
事件,获取用户输入的密码,然后将输入的密码和服务端的密码进行比对,从而实现登录。
onEnd(data) { if (this.password.length) { /* ***********二次认证*********** */ if (this.lockType == 1) { //1、登录 console.log("认证失败次数1:" + this.errorTimes); this.overFailedTimes(); } else if (this.lockType == 2) { //2、注册 this.secondDraw(data); } else if (this.lockType == 3) { //3、修改-重新设置 this.secondDraw(data); } } else { /* ************首次绘制************ */ this.password = data; if (this.lockType == 1) { //1、登录 console.log("认证失败次数1:" + this.errorTimes); if (!this.overFailedTimes()) { //解锁 console.log("密码:" + this.password.join('')); if ((this.password.join('')) == this.serverPwd) { this.text = '解锁成功'; this.needAuthenticate = false; setTimeout(function() { uni.switchTab({ url: '../index/index' }); }, 500); } else { this.certificationFailed(); } this.password = []; } } else if (this.lockType == 2) { //2、注册 this.firstDraw(); } else if (this.lockType == 3) { //3、修改密码 if (this.needAuthenticate) { console.log("认证失败次数1:" + this.errorTimes); if (!this.overFailedTimes()) { //修改需要先认证 console.log("修改-密码认证:" + this.password.join('')); if ((this.password.join('')) == this.serverPwd) { uni.showToast({ title: "手势认证通过", icon: "success", duration: 500 }); this.text = '手势认证通过'; this.pwdError = false; setTimeout(res => { this.text = '绘制你的手势图案,至少连接4个点'; this.needAuthenticate = false; }, 800); } else { this.certificationFailed(); } this.password = []; } } else { //修改密码-第一次绘制(认证通过) this.firstDraw(); } } } },
四、完整源码
<template> <view style="height: 100vh;overflow: hidden;"> <view class="lock-tips"> <view class="big-tips" :style="[needAuthenticate&&!pwdError?{color:'#999999'}:needAuthenticate&&pwdError?{color:'#FF0000'}:{color:''}]">{{text}}</view> <view class="small-tips" v-if="lockType == 2 || (lockType == 3 && !needAuthenticate)">请牢记您的密码,忘记后将无法找回</view> </view> <view class="container-lock"> <mpvue-gesture-lock ref="mpvueGestureLock" :containerWidth="screenWidth" :cycleRadius="30" @end="onEnd" :password="password"></mpvue-gesture-lock> </view> <view class="container-confirm" v-if="showLockConfirm"> <view class="lock-reset" @click="resetLock">重绘</view> <view :class="[confirmEnable?'':'disable-confirm']" @click="lockConfirm">确认</view> </view> <view style="position: fixed;top: 20rpx;left: 35%;z-index: 999;"> <soure :url="url"></soure> </view> </view> </template> <script> import mpvueGestureLock from '@/components/mpvueGestureLock/gestureLocker.vue'; export default { components: { mpvueGestureLock }, data() { return { url:'https://ext.dcloud.net.cn/plugin?id=1623', title: "手势图案", password: [], text: '绘制你的手势图案,至少连接4个点', screenWidth: '', //屏幕宽度 screenHeight: '', //屏幕高度 showLockConfirm: false, //是否显示确认 confirmEnable: false, //是否确认可点击 lockType: '', //手势锁认证类型(1-解锁、2、注册、3-修改) serverPwd: '', //用以验证的密码 needAuthenticate: false, //是否需要认证(解锁、修改需要和设定好的密码做认证) pwdError: false, //手势认证是否通过 errorTimes: 0, //认证失败次数(限制) maxErrorTimes: 5, //最多可以失败几次 backNum: 0, } }, onBackPress(e) { if (this.lockType == 1) { this.backNum++; setTimeout(() => { this.backNum = 0; console.log("重置:" + this.backNum); }, 1500); console.log("backNum:" + this.backNum); if (this.backNum == 1) { uni.showToast({ title: "再按一次退出", icon: 'none' }); } else if (this.backNum >= 2) { plus.runtime.quit(); } return true; //返回true禁止默认返回 } else { return false; } }, onLoad(options) { this.getScreenHeight(); this.lockType = options.type; this.serverPwd = options.pwd; console.log("type:" + this.lockType + ";pwd:" + this.serverPwd); if (this.lockType == 1) { this.text = "请绘制您的手势图案"; this.needAuthenticate = true; console.log("need:" + this.needAuthenticate + ";error:" + this.pwdError); } else if (this.lockType == 2) { this.text = "绘制你的手势图案,至少连接4个点"; } else if (this.lockType == 3) { this.text = "请绘制您的手势图案"; this.needAuthenticate = true; } }, methods: { /* 测量屏幕高度,固定手势锁位置 */ getScreenHeight() { //测量屏幕宽度(得到的是px单位) const deviceInfo = uni.getSystemInfoSync(); console.log("设备信息:" + JSON.stringify(deviceInfo)); this.screenWidth = deviceInfo.screenWidth; console.log("屏幕宽高:(" + this.screenWidth + ";" + this.screenHeight + ")"); }, onEnd(data) { if (this.password.length) { /* ***********二次认证*********** */ if (this.lockType == 1) { //1、登录 console.log("认证失败次数1:" + this.errorTimes); this.overFailedTimes(); } else if (this.lockType == 2) { //2、注册 this.secondDraw(data); } else if (this.lockType == 3) { //3、修改-重新设置 this.secondDraw(data); } } else { /* ************首次绘制************ */ this.password = data; if (this.lockType == 1) { //1、登录 console.log("认证失败次数1:" + this.errorTimes); if (!this.overFailedTimes()) { //解锁 console.log("密码:" + this.password.join('')); if ((this.password.join('')) == this.serverPwd) { this.text = '解锁成功'; this.needAuthenticate = false; setTimeout(function() { uni.switchTab({ url: '../index/index' }); }, 500); } else { this.certificationFailed(); } this.password = []; } } else if (this.lockType == 2) { //2、注册 this.firstDraw(); } else if (this.lockType == 3) { //3、修改密码 if (this.needAuthenticate) { console.log("认证失败次数1:" + this.errorTimes); if (!this.overFailedTimes()) { //修改需要先认证 console.log("修改-密码认证:" + this.password.join('')); if ((this.password.join('')) == this.serverPwd) { uni.showToast({ title: "手势认证通过", icon: "success", duration: 500 }); this.text = '手势认证通过'; this.pwdError = false; setTimeout(res => { this.text = '绘制你的手势图案,至少连接4个点'; this.needAuthenticate = false; }, 800); } else { this.certificationFailed(); } this.password = []; } } else { //修改密码-第一次绘制(认证通过) this.firstDraw(); } } } }, /* 注册、修改-第一次绘制手势 */ firstDraw() { if (this.lockType == 1) { console.log("注册-绘制第一次"); } else if (this.lockType == 3) { console.log("修改密码-重新设置第一次"); } if (this.password.length < 4) { this.text = '至少连接4个点,请重新绘制'; this.password = []; } else { this.text = '再次绘制图案进行确认'; this.showLockConfirm = true; } }, /* 注册、修改-第二次绘制手势 */ secondDraw(pwdAgain) { if (this.lockType == 1) { console.log("注册-绘制第二次"); } else if (this.lockType == 3) { console.log("修改密码-重新设置第二次"); } if (this.password.join('') === pwdAgain.join('')) { this.text = '手势设定完成,点击确认完成设定'; this.confirmEnable = true; console.log("密码:" + JSON.stringify(this.password)); // this.password = [] } else { this.text = '两次手势设定不一致' this.confirmEnable = false; this.password = [] } }, /* 检查认证错误次数 */ overFailedTimes() { if (this.errorTimes > this.maxErrorTimes - 1) { uni.showModal({ title: "警告", content: "今日认证失败超过限制次数,你的设备已被锁定!", showCancel: false, confirmText: "好哒" }); this.password = []; return true; } return false; }, /* 手势认证失败 */ certificationFailed() { this.text = '手势认证未通过'; this.pwdError = true; this.needAuthenticate = true; this.errorTimes++; console.log("errorTimes:" + this.errorTimes + ";maxError:" + this.maxErrorTimes + ";error:" + this.pwdError + ";need:" + this.needAuthenticate); }, /* 确认手势密码 */ lockConfirm() { if (this.confirmEnable == true) { console.log("设定密码:" + this.password.join('')); // uni.showToast({ // title: "手势密码设置成功" + this.password.join(''), // icon: 'none', // duration: 1000 // }); setTimeout(function() { uni.navigateBack({ delta: 1 }); }, 500); } else { } }, /* 重绘密码 */ resetLock() { console.log("重绘"); this.text = "绘制你的手势图案,至少连接4个点"; this.password = []; //引入子组件文件,然后用ref给子组件一个id标识,然后通过this.$refs.组件名.组件方法;调用子组件方法 this.$refs.mpvueGestureLock.refesh(); } } } </script> <style lang="scss"> page { background-color: #FFFFFF; } .lock-tips { height: 25%; margin: 0 !important; display: flex; flex-direction: column; align-items: center; text-align: center; justify-content: center; } .big-tips { font-size: 32rpx; color: #333333; text-align: center; font-weight: 500; } .small-tips { font-size: 24rpx; color: #999999; text-align: center; font-weight: 500; margin-top: 20rpx; } .container-lock { background-color: #FCFCFC; } .container-confirm { display: flex; width: 100%; height: 16%; position: absolute; bottom: 0; flex-direction: row; justify-content: space-around; align-items: center; text-align: center; view { color: #666666; font-size: 28rpx; font-weight: 500; text-align: center; flex: 1; width: 80%; margin: 0 5%; height: 100rpx; line-height: 100rpx; border: 1px solid #F0F0F0; border-radius: 50rpx; } .disable-confirm { color: #A0A0A0; background-color: #F5F5F5; } } </style>