login.vue主文件

  1 <template>
2 <div class="login-wrapper">
3 <img src="../../assets/images/logo.png" class="logo" />
4 <div class="login-box">
5 <ul class="login-title-list">
6 <li class="login-title-item active">账号登录</li>
7 <li class="login-title-item">二维码登录</li>
8 </ul>
9 <div class="login-body">
10 <el-form
11 autocomplete="off"
12 :model="loginForm"
13 :rules="loginRules"
14 ref="loginForm"
15 label-position="left"
16 label-width="0px"
17 class="card-box login-form"
18 >
19 <el-form-item prop="username">
20 <svg-icon icon-class="user" class="icon-svg" />
21 <el-input placeholder="请输入邮箱" type="text" v-model="loginForm.username" />
22 </el-form-item>
23 <el-form-item prop="password">
24 <svg-icon icon-class="password" class="icon-svg" />
25 <el-input placeholder="请输入密码" type="password" v-model="loginForm.password" />
26 </el-form-item>
27 <el-form-item prop="verifycode" class="form-item-captcha">
28 <el-input placeholder="请输入验证码" type="captcha" v-model="loginForm.verifycode" />
29 <span @click="refreshCode" class="yzm">
30 <s-identify :identifyCode="identifyCode"></s-identify>
31 </span>
32 </el-form-item>
33 <el-form-item class="login-wrap">
34 <el-button type="primary" :loading="loading" style="width:100%;" @click="handleLogin"
35 >登录</el-button
36 >
37 </el-form-item>
38 </el-form>
39 <div class="login-footer">
40 <el-checkbox v-model="rememberPassword">记住密码</el-checkbox>
41 <span>忘记密码?</span>
42 </div>
43 </div>
44 </div>
45 </div>
46 </template>
47
48 <script>
49 import { mapState } from 'vuex';
50 import SIdentify from './identify.vue';
51 import { encryptDes } from '../../assets/js/utils/des';
52
53 export default {
54 name: 'Login',
55 components: {
56 SIdentify
57 },
58 data() {
59 // 验证码自定义验证规则
60 const validateVerifycode = (rule, value, callback) => {
61 let newVal = value.toLowerCase();
62 let identifyStr = this.identifyCode.toLowerCase();
63 if (newVal === '') {
64 callback(new Error('请输入验证码'));
65 } else if (newVal !== identifyStr) {
66 callback(new Error('验证码不正确!'));
67 } else {
68 callback();
69 }
70 };
71 return {
72 loginForm: {
73 username: '',
74 password: '',
75 verifycode: ''
76 },
77 identifyCodes: '1234567890ABCDEFGHIGKLMNOPQRSTUVWXYZ',
78 identifyCode: '',
79 rememberPassword: true,
80 loading: false,
81 loginRules: {
82 username: [{ required: true, trigger: 'blur', message: '账号不能为空' }],
83 password: [
84 { required: true, message: '请输入密码', trigger: 'blur' },
85 { min: 6, message: '密码长度最少为6位', trigger: 'blur' }
86 ],
87 verifycode: [{ required: true, trigger: 'blur', validator: validateVerifycode }]
88 }
89 };
90 },
91 methods: {
92 // 生成随机数
93 randomNum(min, max) {
94 return Math.floor(Math.random() * (max - min) + min);
95 },
96 // 切换验证码
97 refreshCode() {
98 this.identifyCode = '';
99 this.makeCode(this.identifyCodes, 4);
100 },
101 // 生成四位随机验证码
102 makeCode(o, l) {
103 for (let i = 0; i < l; i++) {
104 this.identifyCode += this.identifyCodes[this.randomNum(0, this.identifyCodes.length)];
105 }
106 },
107 handleLogin() {
108 this.$refs.loginForm.validate(valid => {
109 if (valid) {
110 this.loading = true;
111 const loginParams = {
112 loginUserId: this.loginForm.username,
113 password: encryptDes(this.loginForm.password)
114 };
115 this.$store.dispatch('login', loginParams).then(res => {
116 this.loading = false;
117 if (res.status === 200) {
118 this.$store.commit('SET_USER_INFO', res.data.onlineUserInfo);
119 this.$router.push({ path: '/' });
120 }
121 });
122 } else {
123 return false;
124 }
125 });
126 }
127 },
128 mounted() {
129 // 验证码初始化
130 this.identifyCode = '';
131 this.makeCode(this.identifyCodes, 4);
132 }
133 };
134 </script>

identify.vue文件

  1 <template>
2 <div class="s-canvas">
3 <canvas id="s-canvas" :width="contentWidth" :height="contentHeight"></canvas>
4 </div>
5 </template>
6 <script>
7 export default {
8 name: 'SIdentify',
9 props: {
10 identifyCode: {
11 type: String,
12 default: '1234'
13 },
14 fontSizeMin: {
15 type: Number,
16 default: 28
17 },
18 fontSizeMax: {
19 type: Number,
20 default: 40
21 },
22 backgroundColorMin: {
23 type: Number,
24 default: 180
25 },
26 backgroundColorMax: {
27 type: Number,
28 default: 240
29 },
30 colorMin: {
31 type: Number,
32 default: 50
33 },
34 colorMax: {
35 type: Number,
36 default: 160
37 },
38 lineColorMin: {
39 type: Number,
40 default: 40
41 },
42 lineColorMax: {
43 type: Number,
44 default: 180
45 },
46 dotColorMin: {
47 type: Number,
48 default: 0
49 },
50 dotColorMax: {
51 type: Number,
52 default: 255
53 },
54 contentWidth: {
55 type: Number,
56 default: 112
57 },
58 contentHeight: {
59 type: Number,
60 default: 40
61 }
62 },
63 methods: {
64 // 生成一个随机数
65 randomNum(min, max) {
66 return Math.floor(Math.random() * (max - min) + min);
67 },
68 // 生成一个随机的颜色
69 randomColor(min, max) {
70 let r = this.randomNum(min, max);
71 let g = this.randomNum(min, max);
72 let b = this.randomNum(min, max);
73 return `rgb(${r},${g},${b})`;
74 },
75 drawPic() {
76 let canvas = document.getElementById('s-canvas');
77 let ctx = canvas.getContext('2d');
78 ctx.textBaseline = 'bottom';
79 // 绘制背景
80 ctx.fillStyle = this.randomColor(this.backgroundColorMin, this.backgroundColorMax);
81 ctx.fillRect(0, 0, this.contentWidth, this.contentHeight);
82 // 绘制文字
83 for (let i = 0; i < this.identifyCode.length; i++) {
84 this.drawText(ctx, this.identifyCode[i], i);
85 }
86 this.drawLine(ctx);
87 this.drawDot(ctx);
88 },
89 drawText(ctx, txt, i) {
90 ctx.fillStyle = this.randomColor(this.colorMin, this.colorMax);
91 ctx.font = `${this.randomNum(this.fontSizeMin, this.fontSizeMax)}px SimHei`;
92 let x = (i + 1) * (this.contentWidth / (this.identifyCode.length + 1));
93 let y = this.randomNum(this.fontSizeMax, this.contentHeight - 5);
94 let deg = this.randomNum(-30, 30);
95 // 修改坐标原点和旋转角度
96 ctx.translate(x, y);
97 ctx.rotate((deg * Math.PI) / 270);
98 ctx.fillText(txt, 0, 0);
99 // 恢复坐标原点和旋转角度
100 ctx.rotate((-deg * Math.PI) / 270);
101 ctx.translate(-x, -y);
102 },
103 drawLine(ctx) {
104 // 绘制干扰线
105 for (let i = 0; i < 2; i++) {
106 ctx.strokeStyle = this.randomColor(this.lineColorMin, this.lineColorMax);
107 ctx.beginPath();
108 ctx.moveTo(this.randomNum(0, this.contentWidth), this.randomNum(0, this.contentHeight));
109 ctx.lineTo(this.randomNum(0, this.contentWidth), this.randomNum(0, this.contentHeight));
110 ctx.stroke();
111 }
112 },
113 drawDot(ctx) {
114 // 绘制干扰点
115 for (let i = 0; i < 20; i++) {
116 ctx.fillStyle = this.randomColor(0, 255);
117 ctx.beginPath();
118 ctx.arc(
119 this.randomNum(0, this.contentWidth),
120 this.randomNum(0, this.contentHeight),
121 1,
122 0,
123 2 * Math.PI
124 );
125 ctx.fill();
126 }
127 }
128 },
129 watch: {
130 identifyCode() {
131 this.drawPic();
132 }
133 },
134 mounted() {
135 this.drawPic();
136 }
137 };
138 </script>

用canvas实现验证码的绘制的更多相关文章

  1. canvas实现验证码

    在通常的登录界面我们都可以看到验证码,验证码的作用是检测是不是人在操作,防止机器等非人操作,防止数据库被轻而易举的攻破. 验证码一般用PHP和java等后端语言编写. 但是在前端,用canva或者SV ...

  2. canvas自适应圆形时钟绘制

    前面的话 前面介绍过canvas粒子时钟的绘制,本文将详细介绍canvas自适应圆形时钟绘制 效果演示 最终自适应圆形时钟的效果如下所示 功能分析 下面来分析一下该圆形时钟的功能 [1]静态背景 对于 ...

  3. Canvas:橡皮筋线条绘制

    Canvas:橡皮筋线条绘制 效果演示 实现要点 事件监听 [说明]: 在Canvas中检测鼠标事件是非常简单的,可以在canvas中添加一个事件监听器,当事件发生时,浏览器就会调用这个监听器. 我们 ...

  4. 神奇的canvas——点与线绘制的绚丽动画效果

    代码地址如下:http://www.demodashi.com/demo/11636.html 前言 之前在某网站上看到了一个canvas绘制的动画效果,虽然组成的元素很简单,只有点和线,但是视觉效果 ...

  5. HTML5 Canvas(实战:绘制饼图2 Tooltip)

    继上一篇HTML5 Canvas(实战:绘制饼图)之后,笔者研究了一下如何给饼图加鼠标停留时显示的提示框. Plot对象 在开始Coding之前,笔者能够想到的最easy的方式,就是给饼图的每一个区域 ...

  6. android 开发 View _12_ 用Canvas 绘制一张图片(博客中演示用Canvas画验证码图片)

    package net.yt.yuncare.widgets; import android.graphics.Bitmap; import android.graphics.Canvas; impo ...

  7. 使用canvas元素-art方法绘制圆弧

    最近在学习HTML5,发现canvas真的很棒,canvas元素是一种可供绘图的平面,我们用JavaScript对它进行配置和操作.我这里说一下arc方法绘制圆弧,顺便提一下涉及到的基础知识. 首先看 ...

  8. html5 canvas 笔记三(绘制文本和图片)

    绘制文本 fillText(text, x, y [, maxWidth])   在指定的(x,y)位置填充指定的文本,绘制的最大宽度是可选的. strokeText(text, x, y [, ma ...

  9. 自定义View(4)Canvas和Paint常用绘制函数

    画布Canvas 在Android下进行2D绘图需要Canvas类的支持,它位于"android.graphics.Canvas"包下,直译过来为画布的意思,用于完成在View上的 ...

  10. JavaScript+canvas 利用贝塞尔曲线绘制曲线

    效果图: <body> <canvas id="test" width="800" height="300">< ...

随机推荐

  1. maven使用指定的pom文件构建子模块

    有条件的同学建议直接浏览原文: https://stackoverflow.com/questions/33396390/custom-pom-xml-filename-in-maven-multim ...

  2. com.alibaba.nacos.api.exception.NacosException

    具体异常如下: com.alibaba.nacos.api.exception.NacosException: <html><body><h1>Whitelabel ...

  3. adb shell getprop 获取系统属性

    adb shell getprop 以华为p30为例: [gsm.default.apn]: [gsm.defaultpdpcontext.active]: true [gsm.dualcards.s ...

  4. NC65单据模板公式使用

    单据模板公式使用 (一) 公式使用场景 用户使用产品时,往往对单据上的字段取值有各种不同的需求.为此单据模板提供 了模板公式功能,可以让实施顾问或者用户通过配置各种公式,并且不用修改代码,从 而满足用 ...

  5. MinIO客户端之cp

    MinIO提供了一个命令行程序mc用于协助用户完成日常的维护.管理类工作. 官方资料 mc cp 上传文件至指定桶内,命令如下: ./mc cp ./local.json local1/bkt1/ 控 ...

  6. 从零玩转设计模式之抽象工厂设计模式-chouxiangshejimoshi

    title: 从零玩转设计模式之抽象工厂设计模式 date: 2022-12-08 16:05:03.28 updated: 2022-12-11 23:03:16.842 url: https:// ...

  7. 【Python】【OpenCV】OCR识别(二)——透视变换

    对于OCR技术在处理有角度有偏差的图像时是比较困难的,而水平的图像使用OCR识别准确度会高很多,因为文本通常是水平排列的,而OCR算法一般会假设文本是水平的. 针对上述情况,所以我们在处理有角度的图象 ...

  8. CSS实例-切换开关

    在线展示: 矩形开关 .switch { position: relative; display: inline-block; width: 60px; height: 34px } .switch ...

  9. .NET开源、强大的Web报表统计系统

    前言 今天分享一个.NET开源.强大的Web报表统计系统:CellReport. 项目官方介绍 CellReport 诞生的初衷是为了解决日常快速制作统计报表的需要. CellReport 是一个为复 ...

  10. 2023-11-29:用go语言,给你一个字符串 s ,请你去除字符串中重复的字母,使得每个字母只出现一次。 需保证 返回结果的字典序最小。 要求不能打乱其他字符的相对位置)。 输入:s = “cba

    2023-11-29:用go语言,给你一个字符串 s ,请你去除字符串中重复的字母,使得每个字母只出现一次. 需保证 返回结果的字典序最小. 要求不能打乱其他字符的相对位置). 输入:s = &quo ...