您当前的位置: 首页 > 解决方案

微信小程序 手势解锁组件(无卡顿)

  • 作者: admin
  • 发布于 2018-08-25 13:47:11
  • 来源:  
  • 栏目:解决方案

导语: 代码地址: Mpvue版本: https://github.com/geminate/mpvue-gesture-lock 原生小程序版本:https://github.com/geminate/mini-gesture-lock 一. 简介最近在 开发小程序的

 代码地址: 

Mpvue版本: https://github.com/geminate/mpvue-gesture-lock 
原生小程序版本:https://github.com/geminate/mini-gesture-lock

 

一. 简介

最近在 开发小程序的时候 遇到了这种手势解锁的需求,网上逛了一圈基本都是使用Canvas实现的,经过本人测试,所有使用Canvas实现的解锁组件,在Android实机测试时均存在严重卡顿问题。原因是 小程序的 canvas onTouchMove事件效率很低(2018/08/17 测试),吐槽一句,小程序现在有很多的坑官方都不去处理,论坛里一大堆问题也没人解决。。。。

既然微信官方暂时没有要解决这个问题的意思,那咱们开发者就只能自己想办法了,于是本人**使用 dom 实现 **了一个基础版本的 手势解锁组件,有两个版本,分别使用mpvue 和 小程序原生写法。

效果图:

10.gif

gesture.gif

 

二. 核心实现

由于 mpvue 版本 和 小程序原生版本思路基本一致,仅代码写法略有不同,因此一下均以 mpvue 代码做说明。

  1. 布局代码
 
  1. <div class="gesture-lock"
  2. :class="{error:error}"
  3. :style="{width: containerWidth +'rpx', height:containerWidth +'rpx'}"
  4. @touchstart="onTouchStart"
  5. @touchmove="onTouchMove"
  6. @touchend="onTouchEnd"
  7. >
  8. <!-- 9 个圆 -->
  9. <div v-for="(item,i) in circleArray" :key="i" class="cycle" :class="{check:item.check}"
  10. :style="{left:item.style.left,top:item.style.top,width:item.style.width,height:item.style.width}">
  11. </div>
  12.  
  13. <!-- 已激活锁之间的线段 -->
  14. <div v-for="(item,i) in lineArray" :key="i" class="line"
  15. :style="{left:item.activeLeft,top:item.activeTop,width:item.activeWidth,transform:'rotate('+item.activeRotate+')'}">
  16. </div>
  17.  
  18. <!-- 最后一个激活的锁与当前位置之间的线段 -->
  19. <div class="line"
  20. :style="{left:activeLine.activeLeft,top:activeLine.activeTop,width:activeLine.activeWidth,transform:'rotate('+activeLine.activeRotate+')'}">
  21. </div>
  22. </div>

布局代码主要分为 3 部分:9个圆形锁、已激活的锁之间的线段 和 最后一个激活的锁与当前手指位置之间的线段。全部 线段 与 圆 均通过 dom和样式实现。避免canvas卡顿。

 

2. JS逻辑

(1). 初始化

 
  1. constructor(containerWidth, cycleRadius) {
  2. // ....
  3.  
  4. this.windowWidth = wx.getSystemInfoSync().windowWidth;// 窗口大小(用于rpx 和 px 转换)
  5.  
  6. this.initCircleArray();
  7. }
  8.  
  9. // 初始化 画布上的 9个圆
  10. initCircleArray() {
  11. const cycleMargin = (this.containerWidth - 6 * this.cycleRadius) / 6;
  12. let count = 0;
  13. for (let i = 0; i < 3; i++) {
  14. for (let j = 0; j < 3; j++) {
  15. count++;
  16. this.circleArray.push({
  17. count: count,
  18. x: this.rpxTopx((cycleMargin + this.cycleRadius) * (j * 2 + 1)),
  19. y: this.rpxTopx((cycleMargin + this.cycleRadius) * (i * 2 + 1)),
  20. radius: this.rpxTopx(this.cycleRadius),
  21. check: false,
  22. style: {
  23. left: (cycleMargin + this.cycleRadius) * (j * 2 + 1) - this.cycleRadius + 'rpx',
  24. top: (cycleMargin + this.cycleRadius) * (i * 2 + 1) - this.cycleRadius + 'rpx',
  25. width: this.cycleRadius * 2 + 'rpx',
  26. }
  27. });
  28. }
  29. }
  30. }

初始化的时候,需要将9个圆的对象数组初始化,根据输入的容器宽度 和 锁半径计算出9个锁的位置及对应的css样式。这里需要注意rpx与px之前的转换。

(2). onTouchStart

 
  1. onTouchStart(e) {
  2. this.setOffset(e);
  3. this.checkTouch({x: e.pageX - this.offsetX, y: e.pageY - this.offsetY});
  4. }
  5.  
  6. // 检测当时 触摸位置是否位于 锁上
  7. checkTouch({x, y}) {
  8. for (let i = 0; i < this.circleArray.length; i++) {
  9. let point = this.circleArray[i];
  10. if (this.isPointInCycle(x, y, point.x, point.y, point.radius)) {
  11. if (!point.check) {
  12. this.checkPoints.push(point.count);
  13. if (this.lastCheckPoint != 0) {
  14. // 已激活锁之间的线段
  15. const line = this.drawLine(this.lastCheckPoint, point);
  16. this.lineArray.push(line);
  17. }
  18. this.lastCheckPoint = point;
  19. }
  20. point.check = true;
  21. return;
  22. }
  23. }
  24. }

当手指按下的时候,首先需要获取到 容器的 offset,然后检查当前手指的位置是否位于 锁圆 内部,如果位于内部的化将这个锁变为已激活状态,并压入激活锁数组。

(3). onTouchMove

 
  1. onTouchMove(e) {
  2. this.moveDraw(e)
  3. }
  4.  
  5. // 移动 绘制
  6. moveDraw(e) {
  7. // 画经过的圆
  8. const x = e.pageX - this.offsetX;
  9. const y = e.pageY - this.offsetY;
  10. this.checkTouch({x, y});
  11.  
  12. // 画 最后一个激活的锁与当前位置之间的线段
  13. this.activeLine = this.drawLine(this.lastCheckPoint, {x, y});
  14. }

当手指在按下并移动的时候,实时检查当前手指的位置是否在未激活的锁上,如果位于未激活的锁上,则将其激活并压入激活锁数组,并按顺序绘制激活锁之间的连线。除此之外还需要绘制上一个激活锁到当前手指位置的连线。

(4).onTouchEnd

 
  1. onTouchEnd(e) {
  2. const checkPoints = this.checkPoints;
  3. this.reset();
  4. return checkPoints;
  5. }

手指放开的时候 清空全部状态



温馨提示:这篇文章没有解决您的问题?欢迎添加微信:18948083295,有微信小程序专业人员,保证有问必答。转载本站文章请注明转自http://www.okeydown.com/(微信小程序网)。

  • 微信扫描二维码关注官方微信
  • ▲长按图片识别二维码
关注我们

微信小程序官方微信

栏目最新
栏目推荐
返回顶部