首页 > 其他分享 >前端实现验证码功能

前端实现验证码功能

时间:2024-08-19 10:55:01浏览次数:13  
标签:功能 default 前端 ctx 验证码 randomNum width document

文章目录

需求

前端实现验证码功能
在这里插入图片描述

分析

1. 输入验证

在这里插入图片描述

  • dentify.vue
<template>
  <div class="s-canvas">
    <canvas
      id="s-canvas"
      :width="contentWidth"
      :height="contentHeight"
    ></canvas>
  </div>
</template>
<script>
export default {
  name: "SIdentify",
  props: {
    identifyCode: {
      // 默认注册码
      type: String,
      default: "1234",
    },
    fontSizeMin: {
      // 字体最小值
      type: Number,
      default: 25,
    },
    fontSizeMax: {
      // 字体最大值
      type: Number,
      default: 35,
    },
    backgroundColorMin: {
      // 验证码图片背景色最小值
      type: Number,
      default: 200,
    },
    backgroundColorMax: {
      // 验证码图片背景色最大值
      type: Number,
      default: 220,
    },
    dotColorMin: {
      // 背景干扰点最小值
      type: Number,
      default: 60,
    },
    dotColorMax: {
      // 背景干扰点最大值
      type: Number,
      default: 120,
    },
    contentWidth: {
      // 容器宽度
      type: Number,
      default: 90,
    },
    contentHeight: {
      // 容器高度
      type: Number,
      default: 38,
    },
  },
  methods: {
    // 生成一个随机数
    randomNum(min, max) {
      return Math.floor(Math.random() * (max - min) + min);
    },

    // 生成一个随机的颜色
    randomColor(min, max) {
      let r = this.randomNum(min, max);
      let g = this.randomNum(min, max);
      let b = this.randomNum(min, max);
      return "rgb(" + r + "," + g + "," + b + ")";
    },
    //画图
    drawPic() {
      let canvas = document.getElementById("s-canvas");
      //创建一个2D对象作为上下文。
      let ctx = canvas.getContext("2d");
      ctx.textBaseline = "bottom";
      // 绘制背景
      ctx.fillStyle = "#e6ecfd";
      ctx.fillRect(0, 0, this.contentWidth, this.contentHeight);
      // 绘制文字
      for (let i = 0; i < this.identifyCode.length; i++) {
        this.drawText(ctx, this.identifyCode[i], i);
      }
      this.drawLine(ctx);
      this.drawDot(ctx);
    },
    //在画布上显示数据
    drawText(ctx, txt, i) {
      ctx.fillStyle = this.randomColor(50, 160); // 随机生成字体颜色
      ctx.font =
        this.randomNum(this.fontSizeMin, this.fontSizeMax) + "px SimHei"; // 随机生成字体大小
      let x = (i + 1) * (this.contentWidth / (this.identifyCode.length + 1));
      let y = this.randomNum(this.fontSizeMax, this.contentHeight - 5);
      var deg = this.randomNum(-30, 30);
      // 修改坐标原点和旋转角度
      ctx.translate(x, y);
      ctx.rotate((deg * Math.PI) / 180);
      ctx.fillText(txt, 0, 0);
      // 恢复坐标原点和旋转角度
      ctx.rotate((-deg * Math.PI) / 180);
      ctx.translate(-x, -y);
    },

    // 绘制干扰线
    drawLine(ctx) {
      for (let i = 0; i < 4; i++) {
        ctx.strokeStyle = this.randomColor(100, 200);
        ctx.beginPath();
        ctx.moveTo(
          this.randomNum(0, this.contentWidth),
          this.randomNum(0, this.contentHeight)
        );
        ctx.lineTo(
          this.randomNum(0, this.contentWidth),
          this.randomNum(0, this.contentHeight)
        );
        ctx.stroke();
      }
    },

    // 绘制干扰点
    drawDot(ctx) {
      for (let i = 0; i < 30; i++) {
        ctx.fillStyle = this.randomColor(0, 255);
        ctx.beginPath();
        ctx.arc(
          this.randomNum(0, this.contentWidth),
          this.randomNum(0, this.contentHeight),
          1,
          0,
          2 * Math.PI
        );
        ctx.fill();
      }
    },
  },
  watch: {
    identifyCode() {
      this.drawPic();
    },
  },
  mounted() {
    this.drawPic();
  },
};
</script>
  • index.vue
<template>
  <div class="home">
    <el-row>
      <el-col :span="4"
        ><el-input
          placeholder="请输入验证码"
          v-model="formLogin.code"
        ></el-input
      ></el-col>
      <el-col :span="4">
        <div class="login-code" width="100%" @click="refreshCode">
          <!--验证码组件-->
          <dentify :identifyCode="identifyCode"></dentify></div
      ></el-col>
    </el-row>
    <div><el-button @click="submit">提交</el-button></div>
  </div>
</template>

<script>
import dentify from "./dentify";
export default {
  name: "HomeView",
  components: {
    dentify,
  },
  data() {
    return {
      // 表单提交内容
      formLogin: {
        code: "", //验证码输入框
      },
      identifyCodes: "1234567890abcdefjhijklinopqrsduvwxyz", //随机串内容,从这里随机抽几个显示验证码
      identifyCode: "", //验证码图片内容
    };
  },
  mounted() {
    // 初始化验证码
    this.identifyCode = "";
    //参数:(1)随机串内容。(2)验证码显示位数
    this.makeCode(this.identifyCodes, 4);
  },
  methods: {
    // 重置验证码
    refreshCode() {
      this.identifyCode = "";
      this.makeCode(this.identifyCodes, 4);
    },
    //获取验证码的值
    makeCode(o, l) {
      for (let i = 0; i < l; i++) {
        //通过循环获取字符串内随机几位
        this.identifyCode +=
          this.identifyCodes[this.randomNum(0, this.identifyCodes.length)];
      }
    },
    //随机数字:用于当角标拿字符串的值
    randomNum(min, max) {
      return Math.floor(Math.random() * (max - min) + min);
    },
    submit() {
      console.log("验证码:", this.identifyCode);
      console.log("用户输入的验证码:",this.formLogin.code);
      console.log('是否验证通过:',this.identifyCode==this.formLogin.code);
    },
  },
};
</script>


2. 滑动验证

在这里插入图片描述

  • dentify.vue
<template>
<!-- 滑动验证码 -->
  <div ref="dragDiv" class="drag">
    <div class="drag_bg"></div>
    <div class="drag_text">{{ confirmWords }}</div>
    <div ref="moveDiv" :class="{'handler_ok_bg':confirmSuccess}" class="handler handler_bg"
         style="position: absolute;top: 0px;left: 0px;" @mousedown="mousedownFn($event)"></div>
  </div>
</template>

<script>
  export default {
    data () {
      return {
        beginClientX: 0, /* 距离屏幕左端距离 */
        mouseMoveStata: false, /* 触发拖动状态  判断 */
        maxwidth: '', /* 拖动最大宽度,依据滑块宽度算出来的 */
        confirmWords: '拖动滑块验证', /* 滑块文字 */
        confirmSuccess: false /* 验证成功判断 */
      }
    },
    mounted () {
      this.maxwidth = this.$refs.dragDiv.clientWidth - this.$refs.moveDiv.clientWidth;
      document.getElementsByTagName('html')[0].addEventListener('mousemove', this.mouseMoveFn);
      document.getElementsByTagName('html')[0].addEventListener('mouseup', this.moseUpFn)
    },
    methods: {
      mousedownFn: function (e) {
        if (!this.confirmSuccess) {
          e.preventDefault && e.preventDefault(); // 阻止文字选中等 浏览器默认事件
          this.mouseMoveStata = true;
          this.beginClientX = e.clientX;
        }
      },
      // mousedoen 事件
      successFunction () {
        this.confirmSuccess = true
        this.confirmWords = '验证通过';
        if (window.addEventListener) {
          document.getElementsByTagName('html')[0].removeEventListener('mousemove', this.mouseMoveFn);
          document.getElementsByTagName('html')[0].removeEventListener('mouseup', this.moseUpFn);
        } else {
          document.getElementsByTagName('html')[0].removeEventListener('mouseup', () => {});
        }
        document.getElementsByClassName('drag_text')[0].style.color = '#fff'
        document.getElementsByClassName('handler')[0].style.left = this.maxwidth + 'px';
        document.getElementsByClassName('drag_bg')[0].style.width = this.maxwidth + 'px';
      },
      // 验证成功函数
      mouseMoveFn (e) {
        if (this.mouseMoveStata) {
          let width = e.clientX - this.beginClientX;
          if (width > 0 && width <= this.maxwidth) {
            document.getElementsByClassName('handler')[0].style.left = width + 'px';
            document.getElementsByClassName('drag_bg')[0].style.width = width + 'px';
          } else if (width > this.maxwidth) {
            this.successFunction();
            console.log('验证成功');
          }
        }
      },
      // mousemove事件
      moseUpFn (e) {
        this.mouseMoveStata = false;
        var width = e.clientX - this.beginClientX;
        if (width < this.maxwidth) {
          document.getElementsByClassName('handler')[0].style.left = 0 + 'px';
          document.getElementsByClassName('drag_bg')[0].style.width = 0 + 'px';
        }
      }
    }
  }
</script>

<style scoped>
    .drag{
        position: relative;
        background-color: #e8e8e8;
        width: 100%;
        height: 34px;
        line-height: 34px;
        text-align: center;
    }
    .handler{
        width: 40px;
        height: 32px;
        border: 1px solid #ccc;
        cursor: move;
    }
    .handler_bg{
        background: #fff url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA3hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDIxIDc5LjE1NTc3MiwgMjAxNC8wMS8xMy0xOTo0NDowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo0ZDhlNWY5My05NmI0LTRlNWQtOGFjYi03ZTY4OGYyMTU2ZTYiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NTEyNTVEMURGMkVFMTFFNEI5NDBCMjQ2M0ExMDQ1OUYiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NTEyNTVEMUNGMkVFMTFFNEI5NDBCMjQ2M0ExMDQ1OUYiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo2MTc5NzNmZS02OTQxLTQyOTYtYTIwNi02NDI2YTNkOWU5YmUiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NGQ4ZTVmOTMtOTZiNC00ZTVkLThhY2ItN2U2ODhmMjE1NmU2Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+YiRG4AAAALFJREFUeNpi/P//PwMlgImBQkA9A+bOnfsIiBOxKcInh+yCaCDuByoswaIOpxwjciACFegBqZ1AvBSIS5OTk/8TkmNEjwWgQiUgtQuIjwAxUF3yX3xyGIEIFLwHpKyAWB+I1xGSwxULIGf9A7mQkBwTlhBXAFLHgPgqEAcTkmNCU6AL9d8WII4HOvk3ITkWJAXWUMlOoGQHmsE45ViQ2KuBuASoYC4Wf+OUYxz6mQkgwAAN9mIrUReCXgAAAABJRU5ErkJggg==") no-repeat center;
    }
    .handler_ok_bg{
        background: #fff url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA3hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDIxIDc5LjE1NTc3MiwgMjAxNC8wMS8xMy0xOTo0NDowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo0ZDhlNWY5My05NmI0LTRlNWQtOGFjYi03ZTY4OGYyMTU2ZTYiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NDlBRDI3NjVGMkQ2MTFFNEI5NDBCMjQ2M0ExMDQ1OUYiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NDlBRDI3NjRGMkQ2MTFFNEI5NDBCMjQ2M0ExMDQ1OUYiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDphNWEzMWNhMC1hYmViLTQxNWEtYTEwZS04Y2U5NzRlN2Q4YTEiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NGQ4ZTVmOTMtOTZiNC00ZTVkLThhY2ItN2U2ODhmMjE1NmU2Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+k+sHwwAAASZJREFUeNpi/P//PwMyKD8uZw+kUoDYEYgloMIvgHg/EM/ptHx0EFk9I8wAoEZ+IDUPiIMY8IN1QJwENOgj3ACo5gNAbMBAHLgAxA4gQ5igAnNJ0MwAVTsX7IKyY7L2UNuJAf+AmAmJ78AEDTBiwGYg5gbifCSxFCZoaBMCy4A4GOjnH0D6DpK4IxNSVIHAfSDOAeLraJrjgJp/AwPbHMhejiQnwYRmUzNQ4VQgDQqXK0ia/0I17wJiPmQNTNBEAgMlQIWiQA2vgWw7QppBekGxsAjIiEUSBNnsBDWEAY9mEFgMMgBk00E0iZtA7AHEctDQ58MRuA6wlLgGFMoMpIG1QFeGwAIxGZo8GUhIysmwQGSAZgwHaEZhICIzOaBkJkqyM0CAAQDGx279Jf50AAAAAABJRU5ErkJggg==") no-repeat center;
    }
    .drag_bg{
        background-color: #7ac23c;
        height: 34px;
        width: 0px;
    }
    .drag_text{
        position: absolute;
        top: 0px;
        width: 100%;text-align: center;
        -moz-user-select: none;
        -webkit-user-select: none;
        user-select: none;
        -o-user-select:none;
        -ms-user-select:none;
    }
</style>



  • index.vue
<template>
  <div class="home">
   <!--验证码组件-->
    <dentify></dentify>
  </div>
</template>

3. 拼图验证

在这里插入图片描述

  • 安装插件
npm install vue-puzzle-vcode --save
<template>
    <div>
        <Vcode :show="isShow" @success="success" @close="close" @fail='fail'></Vcode>
        <button @click="submit">登录</button>
    </div>
</template>

<script>
    import Vcode from "vue-puzzle-vcode";
    export default {
        components: {
            Vcode
        },
        data() {
            return {
                isShow: false, // 验证码模态框是否出现
            }
        },
        methods: {
            submit(){
                this.isShow = true;
            },
            // 用户通过了验证
            success(msg){
                this.isShow = false; // 通过验证后,需要手动隐藏模态框
                console.log('验证通过');
            },
            // 用户点击遮罩层,应该关闭模态框
            close(){
                this.isShow = false;
            },
            // 用户验证失败
            fail(){
                console.log('验证失败');
            }
        }
    }
</script>

<style scoped>

</style>


标签:功能,default,前端,ctx,验证码,randomNum,width,document
From: https://blog.csdn.net/qq_53810245/article/details/141170380

相关文章

  • 一款颜值、功能都很能打的 SSH 远程工具
    给大家推荐一个功能强大,跨平台切风格很现代化的SSH管理工具——Xterminal。1、功能特点布局自由命令管理酷炫皮肤在线编辑文件上传方式多样本地融合显示支持rzsz文件断点上传服务器监控2、展示布局自由双击修改标题自由拖拽右侧底部边栏区功......
  • 从0开始搭建个人博客《第八期:前端服务部署》
    目录一、前期准备工作二、博客web端发布流程        (一)源码拉取        (二)修改配置        (三)安装依赖        (四)本地启动        (五)发布生产        (六)配置nginx           (七)访问验证三、博客admin端......
  • 易优searchform功能:文档标题搜索,默认搜索整站-EyouCms手册
    【基础用法】名称:searchform功能:文档标题搜索,默认搜索整站语法:{eyou:searchformtype='default'}     {$field.hidden}{/eyou:searchform}参数:type='default'默认搜索方式,目前暂时只有default;typeid=''默认搜索所有栏目的文档标题,也可以指定栏目id针对某个栏......
  • 易优list功能:获取列表模板中的列表内容-EyouCms手册
    [基础用法]名称:list功能:获取列表模板中的列表内容。语法:{eyou:listpagesize='10'titlelen='30'infolen='160'orderby='add_time'}{$field.title}{/eyou:list}参数:titlelen='30'标题长度infolen='160'表示内容简介长度pagesize=�......
  • vue3 - 详细实现内网使用离线百度地图功能,在vue3中无需网络离线使用百度地图相关功能,
    效果图在vue3、nuxt3项目开发中,完成内网离线使用百度地图详细教程,让vue3网站无需网络就能加载百度地图及相关功能,完整的百度地图离线使用及地图瓦片的下载教程、更新教程等,vue3百度地图内网离线使用显示地图及各种功能,无论js/ts语法都可以使用,详解百度地图离线加载机制及整......
  • 国内Vue.js前端开发的未来:机会与挑战分析
    引言Vue.js是一款渐进式JavaScript框架,因其简单易用、灵活性强而备受开发者青睐。自2014年发布以来,Vue.js在国内外社区中迅速崛起,成为了热门的前端框架之一。本文将深入分析当前国内Vue.js开发的市场行情、未来发展趋势,以及大龄程序员如何在这一领域实现职业提升和转型。......
  • web前端之根据字符串长度从长到短排序、中文字符串优先、样式循环、禁止冒泡、悬浮、
    MENU前言效果图htmlstyleJavaScript前言1、代码段由HTML、CSS(使用Sass语法)和JavaScript组成,创建一个文本框,用户可以在其中输入内容,并通过点击按钮进行操作。2、代码段的主要功能是允许用户输入一系列以、分隔的项,并根据长度对这些项进行排序(中文字符优先),然后......
  • 基于YOLOv8的通用的滑动验证码滑块缺口检测模型
    文章目录前言滑块缺口验证码验证码示例训练步骤总结前言首先放张图片表达此时的心情,同志们节日快乐!!!滑块缺口验证码滑动验证码滑块缺口的位置识别是破解滑块验证码的关键,这里我们尝试使用YOLOV8训练目标检测模型,识别出滑块图片的缺口验证码示例模型通过大批量......
  • 028、Vue3+TypeScript基础,使用路由功能实现页面切换效果
    01、在main.js中引入路由并使用路由,代码如下://引入createApp用于创建Vue实例import{createApp}from'vue'//引入App.vue根组件importAppfrom'./App.vue'//引入路由importrouterfrom'./router'constapp=createApp(App);//使用路由app.use(router);//App......
  • 027、Vue3+TypeScript基础,使用自定义hook,把功能计算都放到hook中精简代码
    01、在view中创建myhook文件夹,并创建2个文件。usesDog.ts代码如下:import{onMounted,reactive}from"vue";importaxiosfrom"axios";exportdefaultfunction(){//抓取图片letdogList=reactive(['https://images.dog.ceo/breeds/pembro......