摘要:本文给出了一个小程序手势图案锁屏、解锁实现方案,该方案具有重绘少、屏幕闪烁少,使用简单等优点,并增加了onTouchEnd和onSuccess回调,方便大家进行代码扩展,比如可以在onSuccess回调中获取图案密码,存储到数据库等物理介质。

问题由来:小程序目前登陆逻辑是,首次登陆输入用户密码、口令,认证通过后会绑定微信openid,下次进入时只要是同一个微信号(通常openid一致)就直接进入小程序主页面,无需二次输入密码。这种方式简单、高效,但不是很安全,如你手机借他人用下,他人就可以直接进入小程序操作业务啦,为此,打算进入小程序主页面前增加图案解锁(之前没设置的话,先设置图案密码)。

解决思路:度娘看看,有没拿来可用的?还真有,比如:https://www.jb51.net/article/134021.htm(参考方案),下载了DEMO看下,在模拟器上效果还可以,但是在android真机上,有点泪奔,手没怎么划动呢,屏幕就闪个不停。经考量,参考他的思路,重新实现吧。小程序代码片段,DEMO下载!因编辑器URL不支持wechatide协议,请大家复制 wechatide://minicode/U94hICmE7I9m 到浏览器地址栏即可。

一、图案设置、解锁程序演示图如下,具体请大家下载代码片段体验

二、index页面代码

index.wxml

<view class='page'><view class='hd'><text>{{lockType==1?'图案设置' : '图案解锁'}}</text><text class='c-link' wx:if="{{lockType==1}}" bindtap='reset'>重新设置</text><text class='c-link' wx:if="{{lockType==2}}" bindtap='forget'>忘记密码</text></view><view class='bd'><view class='title'>{{lockMsg}}</view><canvas canvas-id="canvas" class="canvas" bindtouchend="onTouchEnd"bindtouchstart="onTouchStart" bindtouchmove="onTouchMove"></canvas></view><view class='ft' style="height:{{ftHeight}}px"><scroll-view scroll-y="true" style="height:100%;"><view class="box"><text>使用说明:</text><text>1) 读取图案密码,密码为空,则进入图案设置模式,反之则进入解锁模式;</text><text>2) 设置模式,点击'重新设置',取消第一次图案绘制,重新绘制;</text><text>3) 解锁模式,点击'忘记密码',重置图案密码,重新设置;</text></view></scroll-view></view>
</view>

index.js

const app = getApp()
const Locker = require('../utils/locker.js');Page({data: {lockMsg: '请绘制图案'},onLoad: function () {let pwd = wx.getStorageSync('locker_pwd') || '';let res = wx.getSystemInfoSync();let ftHeight = res.windowHeight - 410;let that = this;this.setData({ lockType: pwd == '' ? 1 : 2, ftHeight: ftHeight });//this.lock = new Locker(this, {id: 'canvas',lockType: this.data.lockType,onTouchEnd: (e) => {// console.log("onTouchEnd: ", e);},onSuccess: (e) => {// console.log("onSuccess: ", e);if (e.lockType == "1") {console.log("密码设置成功,密码为:", e.lockPwd);that.setData({lockType: 2});that.lock.changeLockType(2);} else {console.log("密码解锁成功!");}}});},reset(e) {this.lock.reset();},forget(e) {let that = this;wx.showModal({content: '确定要重置密码吗?',success:(res)=>{if(res.confirm) {that.setData({lockType: 1});that.lock.changeLockType(1);}}})}
})

index.wxss

.page{background: #f4f4f4; font-size: 14px;}
.hd{padding: 20px; height:20px; line-height: 20px; position: relative; text-align: center;margin-bottom: 20px;
}
.c-link{color:#576b95; height: 20px; position:absolute; right:20px; top:20px;}
.title{font-size: 17px; height: 30px; line-height: 30px; text-align: center}
.canvas {width: 300px;height: 300px;margin: 0 auto;background-color: #f4f4f4;
}
.ft{background:#fff; height:30px;}
.box{padding: 15px; display: flex; flex-direction: column}

三、utils/locker.js

/*** canvasId: 画布ID, 默认'canvas'* lockType: 1--setting, 2--unlock* width: 图案区域宽度,px* successColor: 图案设置或解锁成功时,划过的圆周线颜色* errorColor: 图案设置或解锁失败时,划过的圆周线颜色* cleColor: 9个圆点的圆周线颜色* cleCenterColor: 9个原点的中心小点颜色,及连接线颜色* storageKey: 保存密码的key* onTouchEnd(e): 触摸结束回调* onSuccess(e): 密码设置成功、解锁成功回调*/
var Locker = class {constructor(page,opt){var obj = opt || {};this.page = page;this.width = obj.width || 300;this.height = this.width;this.canvasId = obj.id || 'canvas';this.successColor = obj.successColor || '#00c203';this.errorColor = obj.errorColor || '#e64340';this.cleColor = obj.cleColor || '#3296fa';this.cleCenterColor = obj.cleCenterColor || '#3296fa';this.lockType = obj.lockType || 1;  //1->setting, 2->unlockthis.lockStep = 1;this.lockMsg = "请绘制图案";this.storageKey = obj.storageKey || 'locker_password';this.onTouchEnd = obj.onTouchEnd ? obj.onTouchEnd : function (e) {};this.onSuccess = obj.onSuccess ? obj.onSuccess: function(e) {};this.init();}init(){// 创建 canvas 绘图上下文(指定 canvasId)this.ctx = wx.createCanvasContext(this.canvasId,this);this.touchFlag = false;this.lastPoint = [];//this.createCircles();// canvas绑定事件this.bindEvent();//this.page.setData({ lockMsg: this.lockMsg });//if(this.lockType == 2) {  //读取保存的密码this.savedPwd = wx.getStorageSync(this.storageKey) || '';}}changeLockType(lockType=1) {this.lockType = lockType;if (this.lockType == 2) {  //读取保存的密码this.savedPwd = wx.getStorageSync(this.storageKey) || '';}this.reset();}// 画圆方法drawCircle(x, y, color){color = color || this.cleColor;// 设置边框颜色。this.ctx.setStrokeStyle(color);// 设置线条的宽度。this.ctx.setLineWidth(1);// 开始创建一个路径,需要调用fill或者stroke才会使用路径进行填充或描边。this.ctx.beginPath();this.ctx.arc(x, y, this.r, 0, Math.PI * 2, true);this.ctx.closePath();// 画出当前路径的边框。默认颜色色为黑色。this.ctx.stroke();// 将之前在绘图上下文中的描述(路径、变形、样式)画到 canvas 中。this.ctx.draw(true);}// 创建解锁点的坐标,根据canvas的大小(默认300px)来平均分配半径createCircles() {var n = 3, count = 0;// 计算圆半径this.r = this.width / ((2 * n + 1) * 2);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.width, this.height);// 绘制所有的圆this.arr.forEach(current => { this.drawCircle(current.x, current.y);});}// 获取touch点相对于canvas的坐标getPosition(e) { return {x: e.touches[0].x,y: e.touches[0].y};}// 绘制触摸点drawPoint(x, y, color) { color = color || this.cleCenterColor;this.ctx.setFillStyle(color); // 注意用set方法this.ctx.beginPath();this.ctx.arc(x, y, this.r / 2, 0, Math.PI * 2, true);this.ctx.closePath();this.ctx.fill();this.ctx.draw(true);}drawStatusPoint(color) { // 初始化状态线条for (var i = 0; i < this.lastPoint.length; i++) {this.drawCircle(this.lastPoint[i].x, this.lastPoint[i].y, color);}}drawLine(po1, po2) {this.ctx.beginPath();this.ctx.lineWidth = 2;this.ctx.moveTo(po1.x, po1.y);this.ctx.lineTo(po2.x, po2.y);this.ctx.stroke();this.ctx.closePath();this.ctx.draw(true);  }// 如果po在剩余可用点的圆内,则画触摸点和轨迹线drawTrace(po) {for (var i = 0; i < this.restPoint.length; i++) {var pt = this.restPoint[i];if (Math.abs(po.x - pt.x) < this.r && Math.abs(po.y - pt.y) < this.r) {this.drawPoint(pt.x, pt.y);this.drawLine(this.lastPoint[this.lastPoint.length - 1], pt);this.lastPoint.push(pt);this.restPoint.splice(i, 1);break;}}}reset() {this.lockStep = 1, this.lastPoint = [], this.lockMsg = "请绘制图案";// 绘制圆this.createCircles();//this.page.setData({lockMsg: this.lockMsg});}getLockPwd() {var str = "";for(var i = 0; i<this.lastPoint.length; i++) {str += this.lastPoint[i].index + "";}return str;}bindEvent(){var self = this;this.page.onTouchStart = function(e){console.log("t: ", self.lastPoint);if(self.lastPoint.length > 0) return;   // 上次绘制没有清理干净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;}}}this.page.onTouchMove = function(e){if (self.touchFlag) {self.drawTrace(self.getPosition(e));}}this.page.onTouchEnd = function(e){let success = false;if (self.touchFlag) {self.touchFlag = false;e.lockType = self.lockType;e.lockStep = self.lockStep;e.lockPwd = self.getLockPwd();self.onTouchEnd(e);if(self.lockType == "1") {  // setting pwdif(self.lockStep == 1) {if(e.lockPwd.length < 4) {self.lockMsg = "至少绘制4个及以上点";} else {self.lockMsg = "请再次绘制图案";self.lockPwd = e.lockPwd, self.lockStep++;}} else {if(e.lockPwd == self.lockPwd) {self.lockMsg = "图案绘制成功";self.drawStatusPoint(self.successColor);wx.setStorageSync(self.storageKey,e.lockPwd);success = true;} else {self.drawStatusPoint(self.errorColor);self.lockMsg = "两次不一致,请重新绘制";}}} else {  // unlock pwdif(e.lockPwd == self.savedPwd) {self.lockMsg = "图案解锁成功";self.drawStatusPoint(self.successColor);success = true;} else {self.drawStatusPoint(self.errorColor);self.lockMsg = "图案错误, 请重新绘制";}}self.page.setData({lockMsg: self.lockMsg});setTimeout(function () {self.lastPoint = [], self.createCircles();if(success) {self.onSuccess(e);}}, 1000);}}}
}
module.exports = Locker;

四、与参考方案比较

首先非常感谢参考方案作者给提供思路,并声明方案无好坏,只有适合与否。本实现方案与参考方案比,有两个显著差异。

1、去掉参考方案轨迹指示线功能,取而代之的是目标点自动吸附,解决屏幕重绘、闪烁问题;

2、增加onTouchEnd和onSuccess回调,图案设置成功或解锁成功都会进行onSuccess回调。

微信小程序手势图案锁屏、解锁实现并提供onSuccess等回调相关推荐

  1. 微信小程序----手势图案锁屏

    效果体验二维码 如果文章对你有帮助的话,请打开微信扫一下二维码,点击一下广告,支持一下作者!谢谢! DEMO下载 参考 H5lock 效果图 WXML <view class="con ...

  2. php 手势验证码,通过微信小程序如何实现手势图案锁屏

    这篇文章主要为大家详细介绍了微信小程序实现手势图案锁屏功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 本文实例为大家分享了微信小程序手势图案锁屏的具体代码,供大家参考,具体内容如下 参考 H5 ...

  3. 微信小程序实现图案绘制

    微信小程序实现图案绘制 如图 直接贴代码 1,wxml <view class='page'><view class='hd'><text>{{lockType== ...

  4. uniapp 判断页面是否是横竖屏,解决微信小程序video组件全屏播放视频遮盖自定义播放控件问题

    如果res.deviceOrientation 等于landscape 的话是竖屏,portrait则是横屏.因为用户每旋转一次屏幕就会触发里面的onShow钩子,因此在页面显示或横竖屏变化都会触发这 ...

  5. 微信小程序背景图片全屏显示

    微信小程序背景图片全屏显示 很多人在写小程序界面的时候希望背景图片是全屏覆盖显示的(包括顶部导航栏,如下图),那该如何实现呢? 以下是实现代码: wxml代码: <view class=&quo ...

  6. 【无标题】uniapp中页面跳转白屏 微信小程序跳转白屏

    微信小程序tab切换白屏 这几个图标切换会出现短暂的白屏解决方法如下 组件引入 1.先在common 下建立一个文件夹mixin 下 lodaingPlus.vue 组件 <template&g ...

  7. 微信小程序----手势锁详解

    设计思路流程图 1.全局常量 constructor(page,opts){// 初始化全局常量数据this.page = page;this.width = opts.width || 300;th ...

  8. 【微信技术-微信小程序】------- 渐进式骨架屏(加载流)(第二篇)

    提示:看如下内容需要了解第一篇:简单入门(骨架屏(加载流) 简单入门(第一篇)) 目录 一.什么是渐进式骨架屏? 二.实现渐进式骨架屏 三.效果展示 下载示例代码地址: 渐进式骨架屏示例代码-下载 一 ...

  9. 微信小程序开发之全屏显示

    在开发微信小程序的时候,我们会遇到各种坑,但是,这个东东是中国人做的,so...会有很多解决方案来填坑,今天就来填个小程序开发组件全屏的坑. 问题 我的小程序只有一个地图,如下代码,但他不是全屏的, ...

最新文章

  1. Relay IR表示
  2. TCP/IP基础概念及通信过程举例
  3. Vivado 随笔(6) Timing Summary 相关讨论(一)
  4. beautiful sentences
  5. B站就服务器故障致歉:现已陆续恢复正常
  6. GitHub#python#:用自组织映射解决旅行商问题
  7. ibatis学习四---执行流程浅析
  8. html 收藏网站 功能实现,网站常用的收藏网站实现代码
  9. OAuth2资源服务器
  10. 风吹衣袖,月上西楼- 一个技术人员的心声
  11. 服务器安全防护措施有哪些?
  12. IDA 中怎么查看函数的调用关系
  13. 关于虚拟机复制文件时:无法确定本地文件类型。您可能没有执行此操作的权限。 正在取消文件复制操作。的决解方法
  14. 从0开始的网游ARPG实战案例:暗黑战神(第一章至第四章:设计登陆和创建角色功能实现)
  15. linux mysql dengl_linux环境搭建(四)--MYSQL
  16. [渝粤教育] 中国地质大学 大学物理(上) 复习题 (2)
  17. 2018/01/22 爬虫日记
  18. 免费的股票成交额查询接口要到哪里找?
  19. 用sklearn.preprocessing做数据预处理(四)——OneHotEncoder
  20. linux中mut目录,Linux 下常见文件目录及作用

热门文章

  1. 如何理解statsmodels.ols的输出结果?ols计算的线性回归结果以及手动计算的结果的对比
  2. PCB 布局布线小技巧
  3. svn使用openldap验证apache访问方式
  4. 「解决方案」预付费水电及宿舍预付费云平台解决方案
  5. Solidigm正式推出PCIe 4.0 固态盘Solidigm™ P41 Plus
  6. 彻底弄懂@Controller 、@Service、@Component
  7. c语言程序设计复试都考哪些,2016年首都师范大学信息工程学院C语言程序设计考研复试题库...
  8. SQL查询语句分步详解——多字段分组查询
  9. F460最新光猫破解
  10. 网址URL转义,特殊字符编码HTTP URL编码表