VUE 프로젝트 실현 제스처 암호

그것은 원래 페이지로 작성하지만, 다음 로그인 시간을 만들려면 단순히 어셈블리를 작성, 사용해야했다. 매우 가난한 작성 알고뿐만 아니라, 당신은 열두 족장을 계몽 희망

통과하지 못한 부모 요소의 값이, 다음은 (이하 4 이상인 만들 때 암호 길이)를 두 번 입력, 제스처 기본 암호를 만드는 것입니다, 암호는 동일해야합니다

당신이 로그인하는 경우, 부모 구성 요소의 서브 어셈블리를 통과하는 암호를 넣어, 서브 어셈블리가 현재의 입력 암호를 ​​기반으로한다 올바른 판단이며, 콘솔의 특정 구현을 참조

데모 :

부모 구성 요소 값에 의해 전달하고,이 제스처 암호를 생성 하였다되지

 

 

 

 <: fatherPassword = "[1,2,3,4,5]"gestureUnlock> </ gestureUnlock> 부모 요소 마모 값에 로그인 할 때

여기에 올바른 암호와 암호 오류 상황입니다

 

 

 

 

 

 

암호 구성 요소 :

  1 <!--
  2 组件用法:
  3   由父组件传来fatherPassword,不传的话就默认是一个空数组,则此时就是创建密码,需要输入两次相同的密码完成创建
  4   登录时传过来的值是一个长度大于等于4的数组,则此时就是登录,只判断一次
  5 不足之处:
  6   这里圆的半径是25.5,不能写固定值,但我又不想算
  7   还未处理创建或登录成功之后的事情
  8   还有一个就是canvas的高度问题,这里是用的设备高度的86%,如果九个点下面紧挨着有其他按钮的话是点不了的,因为被canvas覆盖了
  9 -->
 10 <template>
 11   <div class="gestureUnlock">
 12     <div class="gesture">
 13       <ul>
 14         <li ref="selectLi" v-for="(item, index) in list" :key="item.id"
 15             :class="{'selectedOuter': password.indexOf(index) !== -1 ? true : false,
 16             'selectedOuter2': password.indexOf(index) !== -1 && redStyle ? true : false}">
 17           <span :class="{'selectedInside': password.indexOf(index) !== -1 ? true : false,
 18                 'selectedInside2': password.indexOf(index) !== -1 && redStyle ? true : false}">
 19             <!--圆心-->
 20             <i ref="selectLiO"></i>
 21           </span>
 22         </li>
 23       </ul>
 24     </div>
 25     <canvas id="canvas"  @touchstart="start" @touchmove="move" @touchend="end">此浏览器不支持canvas</canvas>
 26   </div>
 27 </template>
 28 
 29 <script>
 30   export default {
 31     name: "GestureUnlock",
 32     data () {
 33       return {
 34         list: [
 35           {id:0, top: 0, left: 0, isSelected: false},
 36           {id:1, top: 0, left: 0, isSelected: false},
 37           {id:2, top: 0, left: 0, isSelected: false},
 38           {id:3, top: 0, left: 0, isSelected: false},
 39           {id:4, top: 0, left: 0, isSelected: false},
 40           {id:5, top: 0, left: 0, isSelected: false},
 41           {id:6, top: 0, left: 0, isSelected: false},
 42           {id:7, top: 0, left: 0, isSelected: false},
 43           {id:8, top: 0, left: 0, isSelected: false},
 44         ],
 45         left: [], // 圆心x坐标
 46         top: [], // 圆心y坐标
 47         password: [], // 用来存储创建密码,从上到下,从左到右依次是123,456,789
 48         cas: '', // 画笔
 49         clientWidth: 0,
 50         clientHeight: 0,
 51         isCorrect: true, // 密码是否且是否正确
 52         redStyle: false, // li样式是否为红色
 53         createPassword: Array // 这个用来存一下父组件传过来的fatherPassword,因为子组件不能直接修改父组件传过来的值
 54       }
 55     },
 56     props: {
 57       // 存储确认密码,变成组件后由父组件传过来,默认是空数组
 58       fatherPassword: {
 59         default: ()=>[], // 这个地方不能写成default: []
 60         type: Array
 61       }
 62     },
 63     created () {
 64       // 存一下父组件传过来的fatherPassword,因为子组件不能直接修改父组件传过来的值
 65       this.createPassword = this.fatherPassword
 66     },
 67     methods: {
 68       // 手指点下
 69       start (e) {
 70         if(e.touches.length > 1 || e.scale && e.scale !== 1) { // 多点触碰或者缩放
 71           console.log('这样不行', e)
 72         } else {
 73           console.log('start', e.touches[0].pageX , e.touches[0].pageY)
 74         }
 75       },
 76       // 手指移动
 77       move (e) {
 78         // this.cas.clearRect(0,0,this.clientWidth,100);
 79         let nowLeft = e.touches[0].pageX
 80         let nowTop = e.touches[0].pageY
 81         for (var i = 0; i < this.left.length; i++) {
 82           // 圆心坐标
 83           let oLeft = this.left[i]
 84           let oTop = this.top[i]
 85           // 这样判断的是个正方形,不是圆形
 86           if((oLeft - 25.5) <= nowLeft && nowLeft <= (oLeft + 25.5) && (oTop - 25.5) <= nowTop && nowTop <= (oTop + 25.5)) {
 87             if (this.password.length === 0 && this.password.indexOf(i) === -1) {
 88               this.password.push(i) // 直接存进密码
 89             } else if(this.password.indexOf(i) === -1){
 90               console.log('连中的值:', this.password[this.password.length - 1])
 91               let value = this.password[this.password.length - 1] // 根据此值(下标)找出对应的this.left和this.top
 92               // value是上一个点的值,i是当前连接点的值
 93               // 1-9 9-1、3-7 7-3、2-8 8-2、4-6 6-4
 94               if (i === 0 && value === 8 || i === 8 && value === 0 ||
 95                 i === 2 && value === 6 || i === 6 && value === 2 ||
 96                 i === 1 && value === 7 || i === 7 && value === 1 ||
 97                 i === 3 && value === 5 || i === 5 && value === 3) {
 98                 // this.password中存的是下标
 99                 if (this.password.indexOf(4) === -1) {this.password.push(4)}
100               } else if(i === 2 && value === 0 || i === 0 && value === 2) { // 1-3  3-1
101                 if (this.password.indexOf(1) === -1) {this.password.push(1)}
102               } else if(i === 6 && value === 8 || i === 8 && value === 6){ // 7-9  9-7
103                 if (this.password.indexOf(7) === -1) {this.password.push(7)}
104               }else if(i === 0 && value === 6 || i === 6 && value === 0){ // 1-7  7-1
105                 if (this.password.indexOf(3) === -1) {this.password.push(3)}
106               }else if(i === 2 && value === 8 || i === 8 && value === 2){ // 3-9  9-3
107                 if (this.password.indexOf(5) === -1) {this.password.push(5)}
108               }
109               // 存密码
110               this.password.push(i)
111             }
112           }
113         }
114         this.paint(nowLeft, nowTop, true)
115       },
116       // 画线的方法
117       paint (nowX, nowY, color) {
118         this.cas.clearRect(0,0,this.clientWidth,this.clientHeight); // 每次画都清空整个画布
119         this.cas.beginPath();
120         for (var i = 0; i < this.password .length; i++) {
121           this.cas.lineTo(this.left[this.password [i]], this.top[this.password [i]]); // 从这个开始
122         }
123         this.cas.lineTo(nowX, nowY);
124         if (!color) {
125           this.cas.strokeStyle = '#ff4b4b'
126         } else {
127           this.cas.strokeStyle = '#498bcb'
128         }
129         this.cas.lineJoin = "round"
130         this.cas.lineWidth = 2;
131         this.cas.stroke();
132         // 清除li内圆形区域的线条
133         this.password.forEach((item) => {
134           this.clearArcFun(this.left[item], this.top[item], 25)
135         })
136       },
137       // 清除li内的圆形区域
138       clearArcFun (centerX, centerY, radius) {
139         var stepClear = 1; //别忘记这一步
140         var _this = this
141         clearArc(centerX, centerY, radius);
142         function clearArc(x, y, radius){ // 圆心x,y,半径radius
143           var calcWidth = radius - stepClear;
144           var calcHeight = Math.sqrt(radius * radius - calcWidth * calcWidth);
145           var posX = x - calcWidth;
146           var posY = y - calcHeight;
147           var widthX = 2 * calcWidth;
148           var heightY = 2 * calcHeight;
149           if(stepClear <= radius){
150             _this.cas.clearRect(posX, posY, widthX, heightY);
151             stepClear += 1;
152             clearArc(x, y, radius);
153           }
154         }
155       },
156       // 手指松开
157       end () {
158         console.log('end', this.password)
159         if (this.createPassword.length === 0) { // 创建密码的第一次
160           if(this.password.length >= 4) {
161             // 此时再调用一次paint,传undefined, undefined,避免最后一条多余的线出现
162             this.paint(undefined, undefined, true)
163             // 不变红
164             this.redStyle = false
165             this.createPassword = this.password
166             // 500ms后清空样式
167             console.log('第一次设置密码createPassword:', this.createPassword)
168             console.log('第一次设置密码password:', this.password)
169             setTimeout(() => {
170               this.password = []
171               this.cas.clearRect(0,0,this.clientWidth,this.clientHeight);
172             }, 500)
173           } else {
174             console.log('创建密码时长度小于4')
175             this.paint(undefined, undefined, false)
176             // 长度小于4样式为红色
177             this.redStyle = true
178             // 清空画布,颜色变正常,不然下次输入还是红色
179             setTimeout(() => {
180               this.password = []
181               this.cas.clearRect(0,0,this.clientWidth,this.clientHeight);
182               this.redStyle = false // 颜色变蓝,不然下次输入还是红色
183             }, 500)
184           }
185         } else { // 创建密码的第二次 或者 登录,不管是啥反正都是拿password(第一次输入的密码)和createPassword比较
186           console.log('createPassword.length不为0,进入密码比较环节')
187           console.log('createPassword:', this.createPassword)
188           console.log('password:', this.password)
189           if (this.password.toString() === this.createPassword.toString()) {
190             // 设置/登录成功
191             console.log('设置/登录成功')
192             setTimeout(() => {
193               this.password = []
194               this.cas.clearRect(0,0,this.clientWidth,this.clientHeight);
195               this.redStyle = false // 没true好像就可以没有false,加上吧保险一点
196             }, 500)
197           } else {
198             this.paint(undefined, undefined, false)
199             // 两次输入不一致/密码不正确 样式为红色
200             this.redStyle = true // 有true下面必得有false
201             console.log('失败')
202             // 清空画布,颜色变蓝
203             setTimeout(() => {
204               this.password = [] // 还有蓝色是因为前几个存在于那个数组,得把password清空
205               this.cas.clearRect(0,0,this.clientWidth,this.clientHeight);
206               this.redStyle = false
207               console.log(this.redStyle)
208             }, 500)
209           }
210         }
211       }
212     },
213     mounted() {
214       // 获取到的是每个方块的左上角的位置,再加上25.5就是圆心坐标
215       for (let i = 0; i < this.$refs.selectLiO.length; i++) {
216         this.left.push(this.$refs.selectLiO[i].getBoundingClientRect().left)
217         this.top.push(this.$refs.selectLiO[i].getBoundingClientRect().top)
218       }
219       console.log(this.left)
220       console.log(this.top)
221       this.clientWidth = document.documentElement.clientWidth
222       this.clientHeight = document.documentElement.clientHeight
223       console.log('设备宽高:', this.clientWidth, this.clientHeight)
224       this.cas = document.getElementById('canvas').getContext('2d');
225       // 这个地方我也不知道为什么要用canvas而不是this.cas
226       canvas.width = this.clientWidth;
227       canvas.height = this.clientHeight*0.86;
228     }
229   }
230 </script>
231 
232 <style lang="less" scoped>
233   .gestureUnlock{
234     margin: 0 auto;
235   }
236   .gesture{
237     margin: 1.0rem auto 0;
238     ul{
239       margin: auto;
240       display: flex;
241       width: 8.88rem;
242       height: 8.88rem;
243       justify-content: space-between;
244       align-content: space-between;
245       flex-wrap: wrap;
246       li{
247         display: flex;
248         align-items:center;
249         justify-content:center;
250         margin: 0.45rem 0.45rem;
251         border-radius: 50%;
252         width: 1.2rem;
253         height: 1.2rem;
254         border: 0.08rem solid #e0e0e0;
255         /*宽度是1.2rem,边框是0.08rem,所以半径是0.68rem,1rem=37.5px,所以0.68x37.5 = 25.5px*/
256         span{
257           display: flex;
258           align-items:center;
259           justify-content:center;
260           width: 0.40rem;
261           height: 0.40rem;
262           border-radius: 50%;
263           i{
264             display: inline-block;
265             width: 1px;
266             height: 1px;
267           }
268         }
269       }
270       /*被选中的样式*/
271       .selectedOuter{
272         border: 0.08rem solid #498bcb;
273         .selectedInside{
274           background: #498bcb;
275         }
276       }
277       .selectedOuter2{
278         border: 0.08rem solid #ff4b4b;
279         .selectedInside2{
280           background: #ff4b4b;
281         }
282       }
283     }
284   }
285   #canvas{
286     position: fixed;
287     top:0;
288     left: 0;
289     /*border:1px solid #42b983;*/
290     /*background: rgba(0,0,0,0.1);*/
291   }
292 </style>

 

 

父组件调用:

 1 <template>
 2   <div class="createGesture">
 3     <div class="picture">
 4       <img src="../../assets/images/standard.png" alt="">
 5     </div>
 6     <div class="words">
 7       <p>Confirm gesture password</p>
 8       <p>Draw a pattern connecting at least four dots.</p>
 9     </div>
10     <!--此页面是创建密码,需要输入两次,组件不传值,fatherPassword默认是一个空数组-->
11     <gestureUnlock></gestureUnlock>
12     <!--下面这是模拟登录时传密码过去-->
13     <!--<gestureUnlock :fatherPassword="[1,2,3,4,5]"></gestureUnlock>-->
14     <div class="bottom">
15       <p>You may create the gesture password later in Settings.</p>
16       <button>Skip</button>
17     </div>
18   </div>
19 </template>
20 
21 <script>
22   import gestureUnlock from '../../components/gestureUnlock'
23   export default {
24     name: "createGesture",
25     components: {
26       gestureUnlock
27     }
28   }
29 </script>
30 
31 <style lang="less" scoped>
32   .createGesture{
33     padding: 0 0.5rem;
34     height: 100%;
35   }
36   .picture{
37     padding-top: 0.533rem;
38     text-align: center;
39     img {
40       /*width: 3rem;*/
41       height: 3rem;
42     }
43   }
44   .words{
45     text-align: center;
46     color: #498bcb;
47     p:nth-child(1) {
48       margin: 0.267rem 0;
49       font-size: 0.723rem;
50     }
51     p:nth-child(2) {
52       font-size: 0.373rem;
53     }
54   }
55   .bottom{
56     position: fixed;
57     bottom: 0;
58     left: 0;
59     width: 100%;
60     p{
61       padding: 0 0.5rem;
62       text-align: left;
63     }
64     button{
65       margin: 0.353rem 0 0.337rem;
66       width: 93%;
67       height: 0.933rem;
68       border-radius: 10px;
69       background-image: linear-gradient(#fff, #f5f5f5);
70       border: 1px solid #93bfe6;
71       box-shadow: 0 0 2px #ececec;
72       color: #498bcb;
73     }
74   }
75 </style>

 

추천

출처www.cnblogs.com/wuyufei/p/11996831.html