本文实例为大家分享了vue2实现手势密码功能的具体代码,供大家参考,具体内容如下

组件:

<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)">关闭</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: '',// 公式计算
        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';//密码的点点默认的颜色
        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) { // 初始化状态线条
        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() {// 创建解锁点的坐标,根据canvas的大小来平均分配半径
        var n = this.chooseType;
        var count = 0;
        this.r = this.ctx.canvas.width / (2   4 * n);// 公式计算
        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点相对于canvas的坐标
        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时候调用
        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结束之后对密码和状态的处理
        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');//小点点外圈高亮
            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个点';
 
          } 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不宜触发 所以增加此行代码
          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>

调用:

<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>

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持Devmax。

vue2实现手势密码功能的更多相关文章

  1. Vue如何指定不编译的文件夹和favicon.ico

    这篇文章主要介绍了Vue如何指定不编译的文件夹和favicon.ico,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  2. vue自定义加载指令v-loading占位图指令v-showimg

    这篇文章主要为大家介绍了vue自定义加载指令和v-loading占位图指令v-showimg的示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  3. vue使用动画实现滚动表格效果

    这篇文章主要为大家详细介绍了vue使用动画实现滚动表格效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  4. 关于Vue 监控数组的问题

    这篇文章主要介绍了Vue 监控数组的示例,主要包括Vue 是如何追踪数据发生变化,Vue 如何更新数组以及为什么有些数组的数据变更不能被 Vue 监测到,对vue监控数组知识是面试比较常见的问题,感兴趣的朋友一起看看吧

  5. Vue子组件props从父组件接收数据并存入data

    这篇文章主要介绍了Vue子组件props从父组件接收数据并存入data的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  6. Vue h函数的使用详解

    本文主要介绍了Vue h函数的使用详解,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  7. VUE响应式原理的实现详解

    这篇文章主要为大家详细介绍了VUE响应式原理的实现,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助

  8. vue+Element ui实现照片墙效果

    这篇文章主要为大家详细介绍了vue+Element ui实现照片墙效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  9. vue+elemet实现表格手动合并行列

    这篇文章主要为大家详细介绍了vue+elemet实现表格手动合并行列,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. iview+vue实现导入EXCEL预览功能

    这篇文章主要为大家详细介绍了iview+vue实现导入EXCEL预览功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

随机推荐

  1. js中‘!.’是什么意思

  2. Vue如何指定不编译的文件夹和favicon.ico

    这篇文章主要介绍了Vue如何指定不编译的文件夹和favicon.ico,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  3. 基于JavaScript编写一个图片转PDF转换器

    本文为大家介绍了一个简单的 JavaScript 项目,可以将图片转换为 PDF 文件。你可以从本地选择任何一张图片,只需点击一下即可将其转换为 PDF 文件,感兴趣的可以动手尝试一下

  4. jquery点赞功能实现代码 点个赞吧!

    点赞功能很多地方都会出现,如何实现爱心点赞功能,这篇文章主要为大家详细介绍了jquery点赞功能实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  5. AngularJs上传前预览图片的实例代码

    使用AngularJs进行开发,在项目中,经常会遇到上传图片后,需在一旁预览图片内容,怎么实现这样的功能呢?今天小编给大家分享AugularJs上传前预览图片的实现代码,需要的朋友参考下吧

  6. JavaScript面向对象编程入门教程

    这篇文章主要介绍了JavaScript面向对象编程的相关概念,例如类、对象、属性、方法等面向对象的术语,并以实例讲解各种术语的使用,非常好的一篇面向对象入门教程,其它语言也可以参考哦

  7. jQuery中的通配符选择器使用总结

    通配符在控制input标签时相当好用,这里简单进行了jQuery中的通配符选择器使用总结,需要的朋友可以参考下

  8. javascript 动态调整图片尺寸实现代码

    在自己的网站上更新文章时一个比较常见的问题是:文章插图太宽,使整个网页都变形了。如果对每个插图都先进行缩放再插入的话,太麻烦了。

  9. jquery ajaxfileupload异步上传插件

    这篇文章主要为大家详细介绍了jquery ajaxfileupload异步上传插件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. React学习之受控组件与数据共享实例分析

    这篇文章主要介绍了React学习之受控组件与数据共享,结合实例形式分析了React受控组件与组件间数据共享相关原理与使用技巧,需要的朋友可以参考下

返回
顶部