vue项目中实现手势密码

本来是写在一个页面中的,但后来一想创建和登录的时候都得用,干脆就写成组件吧。自知写的很差,还望各位大佬指教一二

父组件中不传值的话就默认是创建手势密码(创建时密码长度不能小于4),需要输入两次,两次密码必须一致

如果是登录,父组件就把密码传给子组件,子组件就会根据密码判断当前输入是否正确,具体执行时请看控制台

演示:

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

登录时,父组件穿的值为<gestureUnlock :fatherPassword="[1,2,3,4,5]"></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" >
 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>

原文地址:https://www.cnblogs.com/wuyufei/p/11996831.html

时间: 2024-11-08 22:59:54

vue项目中实现手势密码的相关文章

Vue 项目中使用 jsPlumb

jsPlumb 介绍 jsPlumb 是一个强大的 JavaScript 连线库,它可以将 html中 的元素用箭头.曲线.直线等连接起来,适用于开发 Web 上的图表.建模工具.流程图.关系图等. jsPlumb 参考网站 博客园:http://www.cnblogs.com/leomYili/p/6346526.html?utm_source=itdadao&utm_medium=referral 官网:https://www.jsplumbtoolkit.com/ 安装 jsPlumb v

vue项目中使用阿里iconfont图标

在上一篇文章中介绍了如何在vue项目中使用vue-awesome,如果你想了解,请移步<vue项目中使用vue-awesome> 这里介绍一下vue项目中如何使用阿里的iconfont图标库,先看一下官网 可以看到有将近两百万的图标量,可以说我们想要的矢量图图标这里大部分都是有的,下面直接开始如何在vue项目中使用,方法有两种 方法一:简单粗暴法 1.打开 iconFont官网 选择自己喜欢的图标,并且添加购物车 例如我现在选择三个图标 点击购物车,添加至项目 为了方便可以给项目起一个名字 选

如何在Vue项目中使用vw实现移动端适配

https://www.w3cplus.com/mobile/vw-layout-in-vue.html  原文网址 如何在Vue项目中使用vw实现移动端适配 作者:大漠 日期:2018-01-25 点击:10362 vw Layout 布局 Vue mobile 编辑推荐:使用 Coding.net 搭建静态博客,自定义域名,全站 HTTPS 加密,自动实时部署, 立即托管您的网站! 有关于移动端的适配布局一直以来都是众说纷纭,对应的解决方案也是有很多种.在<使用Flexible实现手淘H5页

在vue项目中 如何定义全局变量 全局函数

如题,在项目中,经常有些函数和变量是需要复用,比如说网站服务器地址,从后台拿到的:用户的登录token,用户的地址信息等,这时候就需要设置一波全局变量和全局函数 定义全局变量 原理: 设置一个专用的的全局变量模块文件,模块里面定义一些变量初始状态,用export default 暴露出去,在main.js里面使用Vue.prototype挂载到vue实例上面或者在其它地方需要使用时,引入该模块便可. 全局变量模块文件: Global.vue文件: <script> const serverSr

前端框架Vue.js——vue-i18n ,vue项目中如何实现国际化

每天学习一点点 编程PDF电子书.视频教程免费下载:http://www.shitanlife.com/code 一.前言 趁着10月的最后一天,来写一篇关于前端国际化的实践型博客.国际化应该都不陌生,就是一个网站.应用可以实现语言的切换. 在这就不谈原理,只说说如何实现中英文的切换.做技术的总得先把 demo 做出来嘛. 二.demo 场景需求分析 需求很简单,左上角 ''网易云音乐''就是一个中英文切换的按钮,点击弹出提示框,确认切换语言后,实现英文版本. 切换成英文版本: 三.实现国际化

转:如何在Vue项目中使用vw实现移动端适配

https://www.w3cplus.com/mobile/vw-layout-in-vue.html 有关于移动端的适配布局一直以来都是众说纷纭,对应的解决方案也是有很多种.在<使用Flexible实现手淘H5页面的终端适配>提出了Flexible的布局方案,随着viewport单位越来越受到众多浏览器的支持,因此在<再聊移动端页面的适配>一文中提出了vw来做移动端的适配问题.到目前为止不管是哪一种方案,都还存在一定的缺陷.言外之意,还没有哪一个方案是完美的. 事实上真的不完美

Vue项目中遇到的一些问题总结

一.开发环境使用Ajax请求,报错 网上查的资料,在config中的index.js这样设置 proxyTable:{ '/api':{ target:'', //此处为你的API接口地址 changeOrigin:true, pathRewrite:{ '^/api':'' //这里理解为用api代替target中的地址 } } } 配置完后,请求依然报错,大致是https证书的问题 [HPM] Error occured while trying to proxy request /xxx/

如何在Vue项目中使用Typescript

0.前言 本快速入门指南将会教你如何在Vue项目中使用TypeScript进行开发.本指南非常灵活,它可以将TypeScript集成到现有的Vue项目中任何一个阶段. 1.初始化项目 首先,创建一个新的项目目录. mkdir typescript-vue-tutorial cd typescript-vue-tutorial 接着,在目录中创建如下目录结构. typescript-vue-tutorial/ ├─ dist/ └─ src/ └─ components/ TypeScript文件

如何在Vue项目中给路由跳转加上进度条

1.前言 在平常浏览网页时,我们会注意到在有的网站中,当点击页面中的链接进行路由跳转时,页面顶部会有一个进度条,用来标示页面跳转的进度(如下图所示).虽然实际用处不大,但是对用户来说,有个进度条会大大减轻用户的等待压力,提升用户体验.本篇文章就来教你如何在Vue项目中实现这样的进度条. 2.安装Nprogress 虽然我们也可以自己手动实现这样的功能,但是,nprogress.js已经帮我们把进度条的样式呀,功能呀都已经封装的很好了,既然有现成的轮子,我们就直接使用轮子就好啦! npm inst