index.vue 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. <template>
  2. <view class="gesture-lock" :class="{error:error}" :style="{width: containerWidth +'rpx', height:containerWidth +'rpx'}"
  3. @touchstart.stop="onTouchStart" @touchmove.stop="onTouchMove" @touchend.stop="onTouchEnd">
  4. <!-- 同级 v-for 的 key 重复会有问题,需要套一层。 -->
  5. <!-- 9 个圆 -->
  6. <view>
  7. <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}">
  8. </view>
  9. </view>
  10. <view>
  11. <!-- 已激活锁之间的线段 -->
  12. <view v-for="(item,i) in lineArray" :key="i" class="line" :style="{left:item.activeLeft,top:item.activeTop,width:item.activeWidth,transform:'rotate('+item.activeRotate+')'}">
  13. </view>
  14. </view>
  15. <!-- 最后一个激活的锁与当前位置之间的线段 -->
  16. <view class="line" :style="{left:activeLine.activeLeft,top:activeLine.activeTop,width:activeLine.activeWidth,transform:'rotate('+activeLine.activeRotate+')'}">
  17. </view>
  18. </view>
  19. </template>
  20. <script>
  21. import GestureLock from './gestureLock';
  22. export default {
  23. name: 'index',
  24. props: {
  25. /**
  26. * 容器宽度
  27. */
  28. containerWidth: {
  29. type: [Number, String],
  30. default: 0
  31. },
  32. /**
  33. * 圆的半径
  34. */
  35. cycleRadius: {
  36. type: [Number, String],
  37. default: 0
  38. },
  39. /**
  40. * 已设定的密码
  41. */
  42. password: {
  43. type: Array,
  44. default () {
  45. return []
  46. }
  47. },
  48. },
  49. data() {
  50. return {
  51. gestureLock: {}, // 锁对象
  52. circleArray: [], // 圆对象数组
  53. lineArray: [], // 已激活锁之间的线段
  54. activeLine: {}, // 最后一个激活的锁与当前位置之间的线段
  55. error: false
  56. }
  57. },
  58. methods: {
  59. onTouchStart(e) {
  60. this.gestureLock.onTouchStart(e);
  61. this.refesh();
  62. },
  63. onTouchMove(e) {
  64. this.gestureLock.onTouchMove(e);
  65. this.refesh();
  66. },
  67. onTouchEnd(e) {
  68. const checkPoints = this.gestureLock.onTouchEnd(e);
  69. if (!this.password.length || checkPoints.join('') == this.password.join('')) {
  70. this.refesh();
  71. this.$emit('end', checkPoints);
  72. } else {
  73. this.error = true;
  74. setTimeout(() => {
  75. this.refesh();
  76. this.$emit('end', checkPoints);
  77. }, 800);
  78. }
  79. },
  80. refesh() {
  81. this.error = false;
  82. this.circleArray = this.gestureLock.getCycleArray();
  83. this.lineArray = this.gestureLock.getLineArray();
  84. this.activeLine = this.gestureLock.getActiveLine();
  85. }
  86. },
  87. mounted() {
  88. this.gestureLock = new GestureLock(this.containerWidth, this.cycleRadius);
  89. this.refesh();
  90. }
  91. }
  92. </script>
  93. <style scoped>
  94. .gesture-lock {
  95. margin: 0 auto;
  96. position: relative;
  97. box-sizing: border-box;
  98. overflow: auto;
  99. }
  100. .gesture-lock .cycle {
  101. box-sizing: border-box;
  102. position: absolute;
  103. border: 2px solid #66aaff;
  104. border-radius: 50%;
  105. }
  106. .gesture-lock .cycle.check:after {
  107. content: "";
  108. display: block;
  109. position: absolute;
  110. width: 32%;
  111. height: 32%;
  112. border: 2px solid #66aaff;
  113. border-radius: 50%;
  114. top: 50%;
  115. left: 50%;
  116. transform: translate(-50%, -50%);
  117. }
  118. .gesture-lock .line {
  119. height: 0;
  120. border-top: 2px solid #66aaff;
  121. position: absolute;
  122. transform-origin: left center;
  123. }
  124. .gesture-lock.error .cycle.check,
  125. .gesture-lock.error .cycle.check:after,
  126. .gesture-lock.error .line {
  127. border-color: #ffa197;
  128. }
  129. </style>