그것은 원래 페이지로 작성하지만, 다음 로그인 시간을 만들려면 단순히 어셈블리를 작성, 사용해야했다. 매우 가난한 작성 알고뿐만 아니라, 당신은 열두 족장을 계몽 희망
통과하지 못한 부모 요소의 값이, 다음은 (이하 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>