vue2實(shí)現(xiàn)手勢密碼功能
本文實(shí)例為大家分享了vue2實(shí)現(xiàn)手勢密碼功能的具體代碼,供大家參考,具體內(nèi)容如下
組件:
<template> ? <div class="masks" v-show="currentValue"> ? ? <div class="gesturePwd"> ? ? ? <div class="box"> ? ? ? ? <h4 ref="gestureTitle" class="gestureTitle">請繪制您的圖形密碼</h4> ? ? ? ? <a class="reset" ref="updatePassword" @click="updatePassword()">重置密碼</a> ? ? ? ? <a class="close" ref="updatePassword" @click="closePwd(false)">關(guān)閉</a> ? ? ? ? <canvas ref="canvas"></canvas> ? ? ? </div> ? ? </div> ? </div> </template> ? <script> ? export default { ? ? props: { ? ? ? value: { ? ? ? ? type: Boolean, ? ? ? ? default: false ? ? ? }, ? ? }, ? ? data() { ? ? ? return { ? ? ? ? currentValue: false, ? ? ? ? ctx: '', ? ? ? ? width: 0, ? ? ? ? height: 0, ? ? ? ? devicePixelRatio: 0, ? ? ? ? chooseType: '', ? ? ? ? r: '',// 公式計(jì)算 ? ? ? ? lastPoint: [], ? ? ? ? arr: [], ? ? ? ? restPoint: [], ? ? ? ? pswObj: {step: 2}, ? ? ? ? canvas: '' ? ? ? } ? ? }, ? ? watch: { ? ? ? value: { ? ? ? ? handler: function (val) { ? ? ? ? ? this.currentValue = val ? ? ? ? }, ? ? ? ? immediate: true ? ? ? }, ? ? ? currentValue(val) { ? ? ? ? this.$emit(val ? 'on-show' : 'on-hide') ? ? ? ? this.$emit('input', val) ? ? ? } ? ? }, ? ? created() { ? ? ? if (typeof this.value !== 'undefined') { ? ? ? ? this.currentValue = this.value ? ? ? } ? ? }, ? ? mounted() { ? ? ? this.setChooseType(3); ? ? }, ? ? methods: { ? ? ? closePwd(bol) { ? ? ? ? this.$emit("handPwd",bol); ? ? ? ? this.currentValue = false; ? ? ? }, ? ? ? drawCle(x, y) { // 初始化解鎖密碼面板 小圓圈 ? ? ? ? this.ctx.strokeStyle = '#87888a';//密碼的點(diǎn)點(diǎn)默認(rèn)的顏色 ? ? ? ? this.ctx.lineWidth = 2; ? ? ? ? this.ctx.beginPath(); ? ? ? ? this.ctx.arc(x, y, this.r, 0, Math.PI * 2, true); ? ? ? ? this.ctx.closePath(); ? ? ? ? this.ctx.stroke(); ? ? ? }, ? ? ? drawPoint(style) { // 初始化圓心 ? ? ? ? for (var i = 0; i < this.lastPoint.length; i++) { ? ? ? ? ? this.ctx.fillStyle = style; ? ? ? ? ? this.ctx.beginPath(); ? ? ? ? ? this.ctx.arc(this.lastPoint[i].x, this.lastPoint[i].y, this.r / 2.5, 0, Math.PI * 2, true); ? ? ? ? ? this.ctx.closePath(); ? ? ? ? ? this.ctx.fill(); ? ? ? ? } ? ? ? }, ? ? ? drawStatusPoint(type) { // 初始化狀態(tài)線條 ? ? ? ? for (var i = 0; i < this.lastPoint.length; i++) { ? ? ? ? ? this.ctx.strokeStyle = type; ? ? ? ? ? this.ctx.beginPath(); ? ? ? ? ? this.ctx.arc(this.lastPoint[i].x, this.lastPoint[i].y, this.r, 0, Math.PI * 2, true); ? ? ? ? ? this.ctx.closePath(); ? ? ? ? ? this.ctx.stroke(); ? ? ? ? } ? ? ? }, ? ? ? drawLine(style, po, lastPoint) {//style:顏色 解鎖軌跡 ? ? ? ? this.ctx.beginPath(); ? ? ? ? this.ctx.strokeStyle = style; ? ? ? ? this.ctx.lineWidth = 3; ? ? ? ? this.ctx.moveTo(this.lastPoint[0].x, this.lastPoint[0].y); ? ? ? ? ? for (var i = 1; i < this.lastPoint.length; i++) { ? ? ? ? ? this.ctx.lineTo(this.lastPoint[i].x, this.lastPoint[i].y); ? ? ? ? } ? ? ? ? this.ctx.lineTo(po.x, po.y); ? ? ? ? this.ctx.stroke(); ? ? ? ? this.ctx.closePath(); ? ? ? ? }, ? ? ? createCircle() {// 創(chuàng)建解鎖點(diǎn)的坐標(biāo),根據(jù)canvas的大小來平均分配半徑 ? ? ? ? var n = this.chooseType; ? ? ? ? var count = 0; ? ? ? ? this.r = this.ctx.canvas.width / (2 + 4 * n);// 公式計(jì)算 ? ? ? ? this.lastPoint = []; ? ? ? ? this.arr = []; ? ? ? ? this.restPoint = []; ? ? ? ? var r = this.r; ? ? ? ? for (var i = 0; i < n; i++) { ? ? ? ? ? for (var j = 0; j < n; j++) { ? ? ? ? ? ? count++; ? ? ? ? ? ? var obj = { ? ? ? ? ? ? ? x: j * 4 * r + 3 * r, ? ? ? ? ? ? ? y: i * 4 * r + 3 * r, ? ? ? ? ? ? ? index: count ? ? ? ? ? ? }; ? ? ? ? ? ? this.arr.push(obj); ? ? ? ? ? ? this.restPoint.push(obj); ? ? ? ? ? } ? ? ? ? } ? ? ? ? this.ctx.clearRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height); ? ? ? ? for (var i = 0; i < this.arr.length; i++) { ? ? ? ? ? this.drawCle(this.arr[i].x, this.arr[i].y); ? ? ? ? ? } ? ? ? }, ? ? ? getPosition(e) {// 獲取touch點(diǎn)相對于canvas的坐標(biāo) ? ? ? ? var rect = e.currentTarget.getBoundingClientRect(); ? ? ? ? var po = { ? ? ? ? ? x: (e.touches[0].clientX - rect.left) * this.devicePixelRatio, ? ? ? ? ? y: (e.touches[0].clientY - rect.top) * this.devicePixelRatio ? ? ? ? }; ? ? ? ? return po; ? ? ? }, ? ? ? update(po) {// 核心變換方法在touchmove時候調(diào)用 ? ? ? ? this.ctx.clearRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height); ? ? ? ? for (var i = 0; i < this.arr.length; i++) { // 每幀先把面板畫出來 ? ? ? ? ? this.drawCle(this.arr[i].x, this.arr[i].y); ? ? ? ? } ? ? ? ? this.drawPoint('#27AED5');// 每幀花軌跡 ? ? ? ? this.drawStatusPoint('#27AED5');// 每幀花軌跡 ? ? ? ? this.drawLine('#27AED5', po, this.lastPoint);// 每幀畫圓心 ? ? ? ? for (var i = 0; i < this.restPoint.length; i++) { ? ? ? ? ? if (Math.abs(po.x - this.restPoint[i].x) < this.r && Math.abs(po.y - this.restPoint[i].y) < this.r) { ? ? ? ? ? ? this.drawPoint(this.restPoint[i].x, this.restPoint[i].y); ? ? ? ? ? ? this.lastPoint.push(this.restPoint[i]); ? ? ? ? ? ? this.restPoint.splice(i, 1); ? ? ? ? ? ? break; ? ? ? ? ? } ? ? ? ? } ? ? ? }, ? ? ? checkPass(psw1, psw2) {// 檢測密碼 ? ? ? ? var p1 = '', p2 = ''; ? ? ? ? for (var i = 0; i < psw1.length; i++) { ? ? ? ? ? p1 += psw1[i].index + psw1[i].index; ? ? ? ? } ? ? ? ? for (var i = 0; i < psw2.length; i++) { ? ? ? ? ? p2 += psw2[i].index + psw2[i].index; ? ? ? ? } ? ? ? ? return p1 === p2; ? ? ? }, ? ? ? storePass(psw) {// touchend結(jié)束之后對密碼和狀態(tài)的處理 ? ? ? ? if (this.pswObj.step == 1) { ? ? ? ? ? if (this.checkPass(this.pswObj.fpassword, psw)) { ? ? ? ? ? ? this.pswObj.step = 2; ? ? ? ? ? ? this.pswObj.spassword = psw; ? ? ? ? ? ? this.$refs.gestureTitle.innerHTML = '密碼保存成功'; ? ? ? ? ? ? this.drawStatusPoint('#2CFF26'); ? ? ? ? ? ? this.drawPoint('#2CFF26'); ? ? ? ? ? ? window.localStorage.setItem('passwordxx', JSON.stringify(this.pswObj.spassword)); ? ? ? ? ? ? window.localStorage.setItem('chooseType', this.chooseType); ? ? ? ? ? } else { ? ? ? ? ? ? this.$refs.gestureTitle.innerHTML = '兩次不一致,重新輸入'; ? ? ? ? ? ? this.drawStatusPoint('red'); ? ? ? ? ? ? this.drawPoint('red'); ? ? ? ? ? ? delete this.pswObj.step; ? ? ? ? ? } ? ? ? ? } else if (this.pswObj.step == 2) { ? ? ? ? ? if (this.checkPass(this.pswObj.spassword, psw)) { ? ? ? ? ? ? var gestureTitle = this.$refs.gestureTitle; ? ? ? ? ? ? gestureTitle.style.color = "#2CFF26"; ? ? ? ? ? ? gestureTitle.innerHTML = '解鎖成功'; ? ? ? ? ? ? this.drawStatusPoint('#2CFF26');//小點(diǎn)點(diǎn)外圈高亮 ? ? ? ? ? ? this.drawPoint('#2CFF26'); ? ? ? ? ? ? this.drawLine('#2CFF26', this.lastPoint[this.lastPoint.length - 1], this.lastPoint);// 每幀畫圓心 ? ? ? ? ? ? this.closePwd(true); ? ? ? ? ? } else if (psw.length < 4) { ? ? ? ? ? ? this.drawStatusPoint('red'); ? ? ? ? ? ? this.drawPoint('red'); ? ? ? ? ? ? this.drawLine('red', this.lastPoint[this.lastPoint.length - 1], this.lastPoint);// 每幀畫圓心 ? ? ? ? ? ? var gestureTitle = this.$refs.gestureTitle; ? ? ? ? ? ? gestureTitle.style.color = "red"; ? ? ? ? ? ? gestureTitle.innerHTML = '請連接4個點(diǎn)'; ? ? ? ? ? ? } else { ? ? ? ? ? ? this.drawStatusPoint('red'); ? ? ? ? ? ? this.drawPoint('red'); ? ? ? ? ? ? this.drawLine('red', this.lastPoint[this.lastPoint.length - 1], this.lastPoint);// 每幀畫圓心 ? ? ? ? ? ? var gestureTitle = this.$refs.gestureTitle; ? ? ? ? ? ? gestureTitle.style.color = "red"; ? ? ? ? ? ? gestureTitle.innerHTML = '密碼錯誤'; ? ? ? ? ? } ? ? ? ? } else { ? ? ? ? ? this.pswObj.step = 1; ? ? ? ? ? this.pswObj.fpassword = psw; ? ? ? ? ? this.$refs.gestureTitle.innerHTML = '再次輸入'; ? ? ? ? } ? ? ? }, ? ? ? makeState() { ? ? ? ? if (this.pswObj.step == 2) { ? ? ? ? ? this.$refs.updatePassword.style.display = 'block'; ? ? ? ? ? var gestureTitle = this.$refs.gestureTitle; ? ? ? ? ? gestureTitle.style.color = "#87888a"; ? ? ? ? ? gestureTitle.innerHTML = '請解鎖'; ? ? ? ? } else if (this.pswObj.step == 1) { ? ? ? ? ? this.$refs.updatePassword.style.display = 'none'; ? ? ? ? } else { ? ? ? ? ? this.$refs.updatePassword.style.display = 'block'; ? ? ? ? } ? ? ? }, ? ? ? setChooseType(type) { ? ? ? ? this.chooseType = type; ? ? ? ? this.init(); ? ? ? }, ? ? ? updatePassword() { ? ? ? ? window.localStorage.removeItem('passwordxx'); ? ? ? ? window.localStorage.removeItem('chooseType'); ? ? ? ? this.pswObj = {}; ? ? ? ? this.$refs.gestureTitle.innerHTML = '繪制解鎖圖案'; ? ? ? ? this.reset(); ? ? ? }, ? ? ? initDom() { ? ? ? ? this.chooseType = Number(window.localStorage.getItem('chooseType')) || 3; ? ? ? ? this.devicePixelRatio = window.devicePixelRatio || 1; ? ? ? ? var canvas = this.$refs.canvas; ? ? ? ? var width = this.width || 320; ? ? ? ? var height = this.height || 320; ? ? ? ? // 高清屏鎖放 ? ? ? ? canvas.style.width = width + "px"; ? ? ? ? canvas.style.height = height + "px"; ? ? ? ? canvas.height = height * this.devicePixelRatio; ? ? ? ? canvas.width = width * this.devicePixelRatio; ? ? ? }, ? ? ? init() { ? ? ? ? this.initDom(); ? ? ? ? this.pswObj = window.localStorage.getItem('passwordxx') ? { ? ? ? ? ? step: 2, ? ? ? ? ? spassword: JSON.parse(window.localStorage.getItem('passwordxx')) ? ? ? ? } : {}; ? ? ? ? this.lastPoint = []; ? ? ? ? this.makeState(); ? ? ? ? this.touchFlag = false; ? ? ? ? this.canvas = this.$refs.canvas; ? ? ? ? this.ctx = this.canvas.getContext('2d'); ? ? ? ? this.createCircle(); ? ? ? ? this.bindEvent(); ? ? ? }, ? ? ? reset() { ? ? ? ? this.makeState(); ? ? ? ? this.createCircle(); ? ? ? }, ? ? ? bindEvent() { ? ? ? ? var self = this; ? ? ? ? this.canvas = this.$refs.canvas; ? ? ? ? this.canvas.addEventListener("touchstart", function (e) { ? ? ? ? ? e.preventDefault();// 某些android 的 touchmove不宜觸發(fā) 所以增加此行代碼 ? ? ? ? ? var po = self.getPosition(e); ? ? ? ? ? for (var i = 0; i < self.arr.length; i++) { ? ? ? ? ? ? if (Math.abs(po.x - self.arr[i].x) < self.r && Math.abs(po.y - self.arr[i].y) < self.r) { ? ? ? ? ? ? ? self.touchFlag = true; ? ? ? ? ? ? ? self.drawPoint(self.arr[i].x, self.arr[i].y); ? ? ? ? ? ? ? self.lastPoint.push(self.arr[i]); ? ? ? ? ? ? ? self.restPoint.splice(i, 1); ? ? ? ? ? ? ? break; ? ? ? ? ? ? } ? ? ? ? ? } ? ? ? ? }, false); ? ? ? ? this.canvas.addEventListener("touchmove", function (e) { ? ? ? ? ? if (self.touchFlag) { ? ? ? ? ? ? self.update(self.getPosition(e)); ? ? ? ? ? } ? ? ? ? }, false); ? ? ? ? this.canvas.addEventListener("touchend", function (e) { ? ? ? ? ? if (self.touchFlag) { ? ? ? ? ? ? self.touchFlag = false; ? ? ? ? ? ? self.storePass(self.lastPoint); ? ? ? ? ? ? setTimeout(function () { ? ? ? ? ? ? ? self.reset(); ? ? ? ? ? ? }, 1000); ? ? ? ? ? } ? ? ? ? }, false); ? ? ? } ? ? } ? } </script> ? <style scoped> ? .masks { ? ? text-align: center; ? ? position: fixed; ? ? z-index: 1000; ? ? top: 0; ? ? right: 0; ? ? left: 0; ? ? bottom: 0; ? ? background: rgba(0, 0, 0, 0.6); ? } ? .gesturePwd { ? ? position: fixed; ? ? z-index: 5000; ? ? width: 100%; ? ? height: 100%; ? ? top: 50%; ? ? left: 50%; ? ? -webkit-transform: translate(-50%, -50%); ? ? transform: translate(-50%, -50%); ? ? text-align: center; ? ? border-radius: 3px; ? ? overflow: hidden; ? ? background-color: #000; ? } ? .gestureTitle { ? ? color: #87888a; ? ? margin-top: 85px; ? ? font-size: 20px; ? ? font-weight: normal; ? } ? .box{ ? ? position: absolute; ? ? top:0; ? ? left:0; ? ? right:0; ? ? bottom:0; ? } ? .box a{ ? ? position: absolute; ? ? top: 5px; ? ? color:#fff; ? ? font-size: 13px; ? ? display:block; ? } ? a.reset{ ? ? left: 5px; ? } ? a.close{ ? ? right :5px; ? } ? .box canvas{ ? ? background-color: #000; ? ? display: inline-block; ? ? margin-top: 76px; ? ? width: 320px; ? ? height: 320px; ? } </style>
調(diào)用:
<template> ? <div class="hello"> ? ? <button @click="showClicked" style="width:90px;height:50px;font-size:16px;background-color:#eee">手勢密碼</button> ? ? <pwd v-model="showPwd" @handPwd="handPwd"></pwd> ? </div> </template> ? <script> ? import pwd from '@/components/pwd' ? export default { ? ? name: 'hello', ? ? data() { ? ? ? return { ? ? ? ? showPwd: false ? ? ? } ? ? }, ? ? methods: { ? ? ? showClicked() { ? ? ? ? this.showPwd = true; ? ? ? }, ? ? ? handPwd(val) { ? ? ? ? console.log(val); ? ? ? } ? ? }, ? ? components: { ? ? ? pwd ? ? }, ? } </script>
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
websocket+Vuex實(shí)現(xiàn)一個實(shí)時聊天軟件
這篇文章主要利用websocked 建立長連接,利用Vuex全局通信的特性,以及watch,computed函數(shù)監(jiān)聽消息變化,并驅(qū)動頁面變化實(shí)現(xiàn)實(shí)時聊天,感興趣的可以了解一下2021-08-08分析 Vue 中的 computed 和 watch 的區(qū)別
這篇文章分析 Vue 的 computed 和 watch 的區(qū)別,computed 用來監(jiān)控自己定義的變量,頁面上可直接使用。watch 是監(jiān)測 Vue 實(shí)例上的數(shù)據(jù)變動,通俗地講,就是檢測 data 內(nèi)聲明的數(shù)據(jù),需要的朋友可以參考一下2021-09-09Nuxt3嵌套路由,報(bào)錯Failed?to?resolve?component:?NuxtChild的解決
這篇文章主要介紹了Nuxt3嵌套路由,報(bào)錯Failed?to?resolve?component:?NuxtChild的解決方案,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-06-06vue + any-touch實(shí)現(xiàn)一個iscroll 實(shí)現(xiàn)拖拽和滑動動畫效果
這篇文章主要介紹了vue + any-touch實(shí)現(xiàn)一個iscroll實(shí)現(xiàn)拖拽和滑動動畫效果,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-04-04詳解Vue如何進(jìn)行表單聯(lián)動與級聯(lián)選擇
表單聯(lián)動和級聯(lián)選擇是Vue.js中常見的功能,在下面的文章中,我們將討論如何在Vue.js中實(shí)現(xiàn)表單聯(lián)動和級聯(lián)選擇,感興趣的小伙伴可以了解一下2023-06-06Vue使用mixins實(shí)現(xiàn)壓縮圖片代碼
本篇文章主要介紹了Vue使用mixins實(shí)現(xiàn)壓縮圖片代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-03-03vue實(shí)現(xiàn)公告欄文字上下滾動效果的示例代碼
這篇文章主要介紹了vue實(shí)現(xiàn)公告欄文字上下滾動效果的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-06-06vue-photo-preview圖片預(yù)覽失效的問題及解決
這篇文章主要介紹了vue-photo-preview圖片預(yù)覽失效的問題及解決方案,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-09-09