1 <template>
2 <view class="logo-wrapper">
3 <view class="logo-img">
4 <image src="../../static/images/logo-login.png" mode="widthFix" />
5 </view>
6 <view class="form-box">
7 <view class="form-item">
8 <view class="icon-box">
9 <i class="iconfont icon-yonghu"></i>
10 </view>
11 <input class="ipt" v-model="username" type="text" placeholder="用户名" />
12 </view>
13 <view class="form-item">
14 <view class="icon-box">
15 <i class="iconfont icon-mima"></i>
16 </view>
17 <input class="ipt" v-model="password" type="password" placeholder="密码" />
18 </view>
19 <view class="form-item">
20 <view class="icon-box">
21 <i class="iconfont icon-yanzhengma"></i>
22 </view>
23 <input class="ipt short" v-model="capCode" type="text" placeholder="验证码" />
24 <canvas class="canvas" canvas-id="yzmCanvas" id="yzmCanvas" @tap="tapCaptcha"></canvas>
25 </view>
26 <button class="btn-login" @tap="login">登录</button>
27 </view>
28 <view class="bottom-img">
29 <image src="../../static/images/login-bottom.png" mode="widthFix" />
30 </view>
31 </view>
32 </template>
33
34 <script>
35 export default {
36 data() {
37 return {
38 capShow: true,
39 username: '',
40 password: '',
41 capCode: '',
42 uuid: ''
43 }
44 },
45 methods: {
46 async queryCaptcha() {
47 const { data } = await this.$http({
48 url: '/captchaImage',
49 method: 'GET',
50 });
51 this.uuid = data.data.uuid;
52 this.creatCanvas(data.data.image);
53 },
54 tapCaptcha() {
55 this.capShow = false;
56 this.$nextTick(() => {
57 this.capShow = true;
58 this.queryCaptcha();
59 });
60 },
61 //得到随机的颜色值
62 randomColor() {
63 var r = Math.floor(Math.random() * 256);
64 var g = Math.floor(Math.random() * 256);
65 var b = Math.floor(Math.random() * 256);
66 return 'rgb(' + r + ',' + g + ',' + b + ')';
67 },
68 creatCanvas(str) {
69 const ctx = uni.createCanvasContext('yzmCanvas');
70 ctx.setFontSize(28 + Math.floor(Math.random() * 4 - 2));
71 ctx.setFillStyle(this.randomColor());
72 for (let i = 0; i < 4; i++) {
73 ctx.setFontSize(28 + Math.floor(Math.random() * 4 - 2));
74 ctx.fillText(str[i], 20 * i + 10, 32);
75 ctx.setFillStyle(this.randomColor());
76 // 旋转随机在-3到3之间
77 ctx.rotate((Math.floor(Math.random() * 6 - 3) * Math.PI) / 180);
78 }
79 // 直线 begin path
80 for (let i = 0; i < 4; i++) {
81 ctx.beginPath();
82 ctx.setStrokeStyle(this.randomColor());
83 // x/-10~110 y/-10~50
84 ctx.moveTo(
85 Math.floor(Math.random() * 100) + Math.floor(Math.random() * 20 - 10),
86 Math.floor(Math.random() * 40) + Math.floor(Math.random() * 20 - 10)
87 );
88 ctx.lineTo(
89 Math.floor(Math.random() * 100) + Math.floor(Math.random() * 20 - 10),
90 Math.floor(Math.random() * 40) + Math.floor(Math.random() * 20 - 10)
91 );
92 ctx.stroke();
93 }
94 ctx.draw();
95 },
96 async login() {
97 if(this.username === '') {
98 uni.showToast({
99 icon: 'none',
100 title: '请填写用户名'
101 });
102 return;
103 }
104 if(this.password === '') {
105 uni.showToast({
106 icon: 'none',
107 title: '请填写密码'
108 });
109 return;
110 }
111 if(this.capCode === '') {
112 uni.showToast({
113 icon: 'none',
114 title: '请填写验证码'
115 });
116 return;
117 }
118 const { data } = await this.$http({
119 url: '/login',
120 method: 'POST',
121 data: {
122 username: this.username,
123 password: this.password,
124 code: this.capCode,
125 uuid: this.uuid
126 }
127 });
128 uni.setStorageSync('token', data.data.token);
129
130 const res = await this.$http({
131 url: '/personal/userInfo',
132 method: 'GET',
133 data: {
134 token: data.data.token,
135 }
136 });
137 let userInfo = res.data.data;
138 uni.setStorageSync('userInfo', userInfo);
139
140 uni.switchTab({
141 url: '/pages/index/index'
142 });
143 }
144 },
145 onLoad() {
146 this.queryCaptcha();
147 },
148 }
149 </script>
150
151 <style lang="scss">
152 .logo-wrapper {
153 display: flex;
154 flex-direction: column;
155 align-items: center;
156 justify-content: space-between;
157 }
158 .logo-img {
159 width: 590upx;
160 height: 246upx;
161 margin-top: 60upx;
162 }
163 .form-box {
164 width: 560upx;
165 height: 580upx;
166 margin: 30upx 0 140upx 0;
167 }
168 .form-item {
169 width: 100%;
170 height: 82upx;
171 margin-top: 48upx;
172 border-bottom: 1px solid #c1c1c1;
173 display: flex;
174 align-items: center;
175 }
176 .icon-box {
177 width: 50upx;
178 height: 50upx;
179 border-radius: 50%;
180 margin-right: 40upx;
181 text-align: center;
182 line-height: 42upx;
183 background-color: #f0443c;
184 color: #fff;
185 i {
186 font-size: 24upx;
187 }
188 }
189 .ipt {
190 flex: 1;
191 height: 80upx;
192 }
193 .canvas {
194 width: 190upx;
195 height: 68upx;
196 border: 1px solid #f1f1f1;
197 background: #fdfdfd;
198 }
199 .btn-login {
200 margin-top: 84upx;
201 background-color: #f0443c;
202 color: #fff;
203 }
204 .bottom-img {
205 width: 628upx;
206 height: 124upx;
207 // margin: 50upx auto 0;
208 }
209 </style>

canvas验证码 uni-app/小程序的更多相关文章

  1. uni与小程序,vue的区别

    标签区别 uni使用小程序的标签,vue使用web端的标签 标签名变化的: 标签描述\类别 vue uniapp 文本 span\font text 链接 a navigator/ router-li ...

  2. Java生鲜电商平台-APP/小程序接口传输常见的加密算法及详解

    Java生鲜电商平台-APP/小程序接口传输常见的加密算法及详解 说明:Java生鲜电商平台-APP/小程序接口传输常见的加密算法及详解,加密算法,是现在每个软件项目里必须用到的内容. 广泛应用在包括 ...

  3. Java生鲜电商平台-电商中"再来一单"功能架构与详细设计(APP/小程序)

    Java生鲜电商平台-电商中"再来一单"功能架构与详细设计(APP/小程序) 说明:在实际的业务场景中(无论是TO B还是TO C)不管是休闲食品.餐饮.水果.日用百货.母婴等高频 ...

  4. Spring Security 一键接入验证码登录和小程序登录

    最近实现了一个多端登录的Spring Security组件,用起来非常丝滑,开箱即用,可插拔,而且灵活性非常强.我觉得能满足大部分场景的需要.目前完成了手机号验证码和微信小程序两种自定义登录,加上默认 ...

  5. 2018最新版 手机号、验证码正则表达式 jq + 小程序

    HTML: <!-- 表单 --> <input class="weui-input" id="tel" type="tel&quo ...

  6. 小程序学习三 一切的开始app() 小程序的注册

    现在打开 app.js //app.js App({ onLaunch(options) { //小程序初始化 // console.log("小程序初始化", options) ...

  7. 小迪安全 Web安全 基础入门 - 第十天 - 信息打点-APP&小程序篇&抓包封包&XP框架&反编译&资产提取

    一.本节知识点思维导图 二.APP-外在资产收集 1.将APP安装在模拟器中,修改模拟器代理设置,使用Fiddler.Burpsuite.Charles等抓包工具抓取APP访问的http协议数据包,抓 ...

  8. 小迪安全 Web安全 基础入门 - 第三天 - 抓包&封包&协议&APP&小程序&PC应用&WEB应用

    一.抓包工具 1.Fiddler.Fiddler是一个用于HTTP调试的代理服务器应用程序,能捕获HTTP和HTTPS流量,并将其记录下来供用户查看.它通过使用自签名证书实现中间人攻击来进行日志记录. ...

  9. uni微信小程序优化,几行代码就能省100kb的主包空间?

    不是标题党,我们公司的项目确确实实是省下了100kb的主包空间,而且还是在没有牺牲任何的性能和业务的前提下实现的. 但是100kb是根据项目大小,所以你用这个插件可能省下超过100kb或者更少. 直接 ...

  10. uni微信小程序优化,打包后的import vue路径是可删除的

    这次的优化我公司项目主包只减小了32kb,但是减小的不仅仅是主包,所有分包均在没有改动任何业务代码的情况下完成了压缩空间的优化. 主包分包压缩空间的优化都要视项目而定,32kb只是我公司的小程序项目. ...

随机推荐

  1. 用最清爽的方式开发dotNet

    用最清爽的方式开发dotNet 不管是官方自带模板还是其他开源搞的,总是一来一大堆,如果你也嫌弃这些过于臃肿,不如看看我这个方式 前提 假设我要做一个简单的api 方式 想到清爽,那肯定是简单方便,脑 ...

  2. zookeeper JavaApi 删除节点

    /* * 删除节点 * 1.删除单个节点 * 2.删除带有子节点的节点 * 3.必须成功的删除 * 4.回调 * * */ @Test public void delete1() throws Exc ...

  3. 火爆全网的Log4j 漏洞复现GetShell

    目录: 一.搭建环境 1. 首先拉一个docker镜像 2. 然后启动环境 二.获取shell 首先,试验一下DNSLog 1. 准备JNDI注入工具 下载 进入目录打包成jar包 2. 利用 生成p ...

  4. Docker安装 配置

    Docker的技术原理: 1. Linux 命名空间(Namespaces) 进程命名空间:使得每个容器拥有独立的进程空间,互相隔离,不受其他容器影响. 网络命名空间:提供独立的网络栈,每个容器有自己 ...

  5. 十分钟教你在 k8s 中部署一个前后端应用

    转载至我的博客https://www.infrastack.cn ,公众号:架构成长指南 大家好,我是蜗牛哥,好多开发人员,尤其是没接触过 k8s 的人员对如何在k8s中部署一个 前后端应用很模糊,不 ...

  6. LayoutBuilder(获取父类的宽高)

    LayoutBuilder 是 Flutter 中的一个构建组件,用于根据父容器的约束对其子组件进行布局. import 'package:flutter/material.dart'; void m ...

  7. 微信小程序数组

    常用函数 concat(): 连接两个或多个数组,返回连接后的新数组. 示例:const arr1 = [1, 2, 3]; const arr2 = [4, 5, 6]; const arr3 = ...

  8. 你的JoinHint为什么不生效

    本文分享自华为云社区<你的JoinHint为什么不生效[绽放吧!GaussDB(DWS)云原生数仓]>,作者:你是猴子请来的救兵吗 . 引言 提起数据库的Hint,几乎每个DBA都知道这一 ...

  9. 3大方面升级华为云CCE集群体验,助力集群高效运维管理

    本文分享自华为云社区<华为云从心打造CCE集群升级体验,助力集群高效运维管理>,作者:云容器大未来 . 在云原生时代浪潮的推动下,Kubernetes的发展日新月异,更新的集群版本可以带来 ...

  10. CSV:简单格式下隐藏的那些坑

    摘要:本文将盘点处理CSV数据时我遇到的一些坑. 本文分享自华为云社区<CSV-简单格式下隐藏的那些坑>,作者:aKi. 前言 CSV(Comma-Separated Values),是一 ...