vue项目中实现手势密码

您所在的位置:网站首页 excel怎样读音 vue项目中实现手势密码

vue项目中实现手势密码

2023-12-28 02:52| 来源: 网络整理| 查看: 265

tips:本文是做记录用的

思路:

  本来应该全部都用canvas来实现的,但时间紧迫 写的时候只想着圆圈用li写,线用canvas,写到一半才想通,不过还好这一通下来还算比较顺利

  第一步:页面中的9个点用v-for循环出来li,ul设置成宽高相等的正方形。给li设置margin,保证一行只能装得下三个li,然后ul用display:flex;justify-content: space-between; align-content: space-between;给子元素排成九宫格;

  第二步:先获取九个点圆心的位置,在手指按下移动的方法中判断当前手指的坐标是否到li区域内,然后把对应位置的数字存进密码数组,调用画线的方法,把密码数组中的数字对应的点连起来,最后连到手指的位置

  第三步:在手指松开的方法中进行各种判断,判断是创建密码还是登录,判断密码长度是否小于4,有错的话颜色变红,最后再判断密码是否正确

说明:

  1、手势密码部分以组件的形式引入需要用到的页面中

  2、父组件中不传值的话就默认是创建手势密码(创建时密码长度不能小于4),需要输入两次,两次密码必须一致,如果是登录,父组件就把密码传给子组件,子组件就会根据密码判断当前输入是否正确,执行时请看控制台

不足之处:

  1、未处理创建或登录成功之后的事情(写一个emit就行了,把输入的密码传给父组件)

  2、还有一个就是canvas的高度问题,这里是用的设备高度的86%,如果九个点下面紧挨着有其他按钮的话是点不了的,因为被canvas覆盖了

演示:

父组件未传值,此时是创建手势密码

 

 

 

 登录时,父组件穿的值为

下面分别是密码正确和密码错误的情况

 

 

 

 

 

 

密码组件:

1 2 3 4 5 8 10 11 12 13 14 15 16 17 18 此浏览器不支持canvas 19 20 incorrect pattern 21 22 23 24 25 export default { 26 name: "GestureUnlock", 27 data () { 28 return { 29 list: [ 30 {id:0, top: 0, left: 0, isSelected: false}, 31 {id:1, top: 0, left: 0, isSelected: false}, 32 {id:2, top: 0, left: 0, isSelected: false}, 33 {id:3, top: 0, left: 0, isSelected: false}, 34 {id:4, top: 0, left: 0, isSelected: false}, 35 {id:5, top: 0, left: 0, isSelected: false}, 36 {id:6, top: 0, left: 0, isSelected: false}, 37 {id:7, top: 0, left: 0, isSelected: false}, 38 {id:8, top: 0, left: 0, isSelected: false}, 39 ], 40 left: [], // 圆心x坐标 41 top: [], // 圆心y坐标 42 password: [], // 用来存储创建密码,从上到下,从左到右依次是123,456,789 43 cas: '', // 画笔 44 casClearTop:'', // 上部清除线条的画布对象 45 clientWidth: 0, 46 clientHeight: 0, 47 isCorrect: true, // 密码是否且是否正确 48 redStyle: false, // li样式是否为红色 49 createPassword: Array, // 这个用来存一下父组件传过来的fatherPassword,因为子组件不能直接修改父组件传过来的值 50 radius: Number, // 半径 51 tips: false // 错误提示是否显示 52 } 53 }, 54 props: { 55 // 存储确认密码,变成组件后由父组件传过来,默认是空数组 56 fatherPassword: { 57 default: ()=>[], // 这个地方不能写成default: [] 58 type: Array 59 } 60 }, 61 created () { 62 // 存一下父组件传过来的fatherPassword,因为子组件不能直接修改父组件传过来的值 63 this.createPassword = this.fatherPassword 64 }, 65 mounted() { 66 // 获取到的是每个方块中心i标签的位置, 67 for (let i = 0; i < this.$refs.selectLiO.length; i++) { 68 this.left.push(this.$refs.selectLiO[i].getBoundingClientRect().left) 69 this.top.push(this.$refs.selectLiO[i].getBoundingClientRect().top) 70 } 71 this.radius = this.$refs.selectLiO[0].getBoundingClientRect().left - this.$refs.selectLi[0].getBoundingClientRect().left 72 console.log('半径为:', this.radius) 73 console.log(this.left) 74 console.log(this.top) 75 this.clientWidth = document.documentElement.clientWidth 76 this.clientHeight = document.documentElement.clientHeight 77 console.log('设备宽高:', this.clientWidth, this.clientHeight) 78 this.cas = document.getElementById('canvas').getContext('2d'); 79 document.getElementById('canvas').width = this.clientWidth; 80 // canvas高度为最后一个圆的圆心加半径乘以1.5,就是大于最后一行多一点 81 document.getElementById('canvas').height = this.top[this.top.length-1] + this.radius*1.5; 82 // this.casClearTop = document.getElementById('canvasClearTop').getContext('2d'); 83 // document.getElementById('canvasClearTop').width = this.clientWidth; 84 // document.getElementById('canvasClearTop').height = this.top[0] - this.radius*1.5; 85 }, 86 methods: { 87 // 手指点下 88 start (e) { 89 if(e.touches.length > 1 || e.scale && e.scale !== 1) { // 多点触碰或者缩放 90 console.log('这样不行', e) 91 } else { 92 console.log('start', e.touches[0].pageX , e.touches[0].pageY) 93 } 94 }, 95 // 手指移动 96 move (e) { 97 // this.casClearTop.clearRect(0,0,200,200); 98 let nowLeft = e.touches[0].pageX 99 let nowTop = e.touches[0].pageY 100 for (var i = 0; i < this.left.length; i++) { 101 // 圆心坐标 102 let oLeft = this.left[i] 103 let oTop = this.top[i] 104 if((oLeft - this.radius) { 218 this.password = [] 219 this.cas.clearRect(0,0,this.clientWidth,this.clientHeight); 220 this.redStyle = false // 没true好像就可以没有false,加上吧保险一点 221 }, 500) 222 } else if(this.password.length !== 0){ // 两次输入不一致/密码不正确 这里写this.password.length !== 0是为了防止点一下canvas也会出现输入错误的提示 223 this.tips = true 224 this.paint(undefined, undefined, false) 225 // 两次输入不一致/密码不正确 样式为红色 226 this.redStyle = true // 有true下面必得有false 227 console.log('失败') 228 // 清空画布,颜色变蓝 229 setTimeout(() => { 230 this.password = [] // 还有蓝色是因为前几个存在于那个数组,得把password清空 231 this.cas.clearRect(0,0,this.clientWidth,this.clientHeight); 232 this.redStyle = false 233 console.log(this.redStyle) 234 }, 500) 235 } 236 } 237 } 238 } 239 } 240 241 242 243 .incorrectTip{ 244 height: .5rem; 245 span{ 246 /*line-height: .8rem;*/ 247 color: #ff4b4b; 248 } 249 } 250 .gestureUnlock{ 251 margin: 0 auto; 252 } 253 .gesture{ 254 margin: 1.0rem auto 0; 255 ul{ 256 margin: auto; 257 display: flex; 258 width: 8.88rem; 259 height: 8.88rem; 260 justify-content: space-between; 261 align-content: space-between; 262 flex-wrap: wrap; 263 li{ 264 display: flex; 265 align-items:center; 266 justify-content:center; 267 margin: 0.45rem 0.45rem; 268 border-radius: 50%; 269 width: 1.2rem; 270 height: 1.2rem; 271 border: 0.08rem solid #e0e0e0; 272 /*宽度是1.2rem,边框是0.08rem,所以半径是0.68rem,1rem=37.5px,所以0.68x37.5 = 25.5px*/ 273 span{ 274 display: flex; 275 align-items:center; 276 justify-content:center; 277 width: 0.40rem; 278 height: 0.40rem; 279 border-radius: 50%; 280 i{ 281 display: inline-block; 282 width: 1px; 283 height: 1px; 284 } 285 } 286 } 287 /*被选中的样式*/ 288 .selectedOuter{ 289 border: 0.08rem solid #498bcb; 290 .selectedInside{ 291 background: #498bcb; 292 } 293 } 294 .selectedOuter2{ 295 border: 0.08rem solid #ff4b4b; 296 .selectedInside2{ 297 background: #ff4b4b; 298 } 299 } 300 } 301 } 302 .canvasDiv{ 303 position: fixed; 304 top:0; 305 left: 0; 306 // background: rgba(0,0,0,0.1); 307 z-index: 100; 308 #canvasClearTop{ 309 position: absolute; 310 top: 0; 311 left: 0; 312 background: rgba(255,0,0,0.2) 313 } 314 }315

 

 

父组件调用(创建密码):

1 2 3 4 5 6 7 8

{{$t('createGesture.createGesture')}}

9

{{$t('createGesture.drawTips')}}.

10

{{$t('createGesture.confirmGesture')}}

11

{{$t('createGesture.drawTips2')}}.

12 13 14 15 16 17 18 19

{{$t('createGesture.bottomTips')}}.

20 21 {{$t('createGesture.skip')}} 22 23 24 25 26 27 28 import gestureUnlock from '../../components/gestureUnlock' 29 import Vue from 'vue'; 30 import { Grid, GridItem } from 'vant'; 31 Vue.use(Grid).use(GridItem); 32 export default { 33 name: "createGesture", 34 components: { 35 gestureUnlock 36 }, 37 data() { 38 return { 39 logoImg: require('./Zurich_logo.png'), 40 firstPwd: '', // 用来存创建密码时第一次输入的密码,便于和第二次比较 41 regOrLogin: 'reg', // 传给子组件用于判断是注册还是登陆 42 isShowConfirm: false, // 是否显示confirm密码 43 } 44 }, 45 methods: { 46 onceDraw (e) { 47 if (e.success) { 48 console.log('第一次') 49 this.isShowConfirm = true 50 } 51 }, 52 fromNinePoint (e) { 53 if(e.success) { 54 console.log('父组件:', e.pwd, '手势密码设置完成,登录') 55 this.send(e.pwd.join('')) 56 } 57 }, 58 send (gesPwd) { 59 console.log('手势密码:', gesPwd) 60 this.$axios.post('http://*****/*****/****/gesturePasswordSetup', { 61 username: '123', 62 gesturePassword: gesPwd, // 手势密码 63 }) 64 .then((res) => { 65 console.log('返回的数据:', res) 66 let flag = res.data.flagStr 67 if (flag === 'Succ') { 68 console.log('设置成功') 69 } 70 }) 71 .catch((res) => { 72 console.log('报错:', res) 73 }) 74 }, 75 // 跳过 76 skip () { 77 this.$router.push({name: '/'}) 78 } 79 } 80 } 81 82 83 84 .createGesture{ 85 height: 100%; 86 } 87 .picture{ 88 padding-top: 0.533rem; 89 text-align: center; 90 img { 91 height: 3rem; 92 } 93 } 94 .words{ 95 text-align: center; 96 color: #498bcb; 97 p:nth-child(1) { 98 margin: 0.267rem 0; 99 font-size: 0.723rem; 100 } 101 p:nth-child(2) { 102 font-size: 0.373rem; 103 } 104 } 105 .bottom{ 106 z-index: 2000; 107 margin-top: .3rem /* 30/37.5 */; 108 width: 100%; 109 p{ 110 padding: 0 0.5rem; 111 font-size: inherit; 112 } 113 div{ 114 margin: 0.353rem 0 0.337rem; 115 } 116 } 117


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3