使用html和js和svg实现的一个简单小练习登录页面中的验证码,大概功能主要是:
点击看不清换一张会重新生成验证码,验证码中包含数字、线条、字母。该验证码是通过svg实现。详细的解释和代码步骤我都注释在下面的代码中的,请君一阅。
【注:仅作自己查看和分享学习之用】
【效果如图】
代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>登录页面</title>
/* 我这里重置了所有样式,如要使用代码,记得注意重置样式问题 */
<link rel="stylesheet" href="../reset.css">
</head>
<style>
body {
background-color: skyblue;
height: 555px;
background-size: cover;
}
section {
width: 600px;
/* height: 500px; */
border-radius: 50px;
box-sizing: border-box;
margin: 120px auto;
padding: 60px;
background-color: rgba(255, 255, 255, 0.7);
line-height: 60px;
}
h1 {
font-size: 30px;
margin-top: -20px;
padding-bottom: 10px;
}
section>div {
margin-left: 50px;
margin-top: 20px;
}
input {
width: 350px;
height: 40px;
font-size: 15px;
border-radius: 18px;
border: 1px solid rgb(120, 120, 120);
padding-left: 26px;
font-family: 'Courier New', Courier, monospace;
letter-spacing: 1px;
}
form>p>a {
text-decoration: none;
color: red;
}
form>p>label {
letter-spacing: 1px;
font-family: 'Courier New', Courier, monospace;
}
form>p>label>a {
text-decoration: none;
color: rgb(60, 60, 168);
}
form>p>label>a:hover {
color: rgb(249, 98, 44);
}
button {
width: 380px;
height: 40px;
border-radius: 30px;
font-size: 17px;
border: 1px solid rgb(120, 120, 120);
font-family: 'Courier New', Courier, monospace;
}
form>p:nth-child(3) {
width: 380px;
margin-top: 15px;
display: flex;
padding: 0 5px;
box-sizing: border-box;
justify-content: space-between;
}
#inputCode{
width: 100px;
height: 40px;
border-radius: 0;
padding-left: 15px;
}
svg{
width: 130px;
height: 40px;
border: 1px solid;
}
.shuaxin{
font-size: 12px;
color: blue;
}
.shuaxin:hover{
text-decoration: underline;
color: red;
}
form>p:nth-of-type(4) {
margin-left: 235px;
font-size: 14px;
letter-spacing: 1px;
font-family: 'Courier New', Courier, monospace;
}
</style>
<body>
<!-- 账号和密码,
登录成功则跳转index页面,
登录失败,则留在原页面,并告知哪里填写错误。 -->
<section>
<div>
<h1>登录页面!</h1>
<form action="#" method="get">
<p>
<input type="text" placeholder="用户名:" name="username" id="username" required>
</p>
<p>
<input type="password" placeholder="密码:" name="password" id="password" required>
</p>
<p>
<input type="text" name="" id="inputCode" placeholder="验证码">
<svg></svg>
<a href="" class="shuaxin">看不清?换一张</a>
</p>
<button id="login">登录</button>
<p>没有账号?<a href="./reg.html">立即注册</a></p>
</form>
</div>
</section>
<script src="./js/login.js"></script>
</body>
</html>
let inpEle = document.querySelectorAll("input");
let btn = document.getElementsByTagName("button")[0];
let form = document.getElementsByTagName("form")[0];
let svgEle = document.getElementsByTagName("svg")[0];
let shuaxin = document.getElementsByClassName("shuaxin")[0];
btn.addEventListener("click", function (event) {
//获取用户的数据
let username = inpEle[0].value;
let pwd = inpEle[1].value;
//获取验证码框的信息
let code = svgEle.dataset.str;
let admin = JSON.parse(localStorage.getItem("users"));
let arr = admin.filter(item => item.username == username && item.password == pwd);
if (arr.length > 0) {
//把输入框的输入的字母全都转成小写与svg标签里面的字符串进行对比
//因为str基础数据字符串里就全是小写字母,在渲染的时候其中有部分会随机渲染成大写字母,但这并不影响最开始拿到的那个随机生成的字符串
if (inpEle[2].value.toLowerCase() === code) {
alert("恭喜您登录成功!");
form.action = "./index.html";
} else {
alert("验证码错误!");
inpEle[2].value = "";
codeRender();
}
} else {
alert("账号或密码错误,请重新输入!");
[...inpEle].forEach(item => item.value = "");
codeRender();
event.preventDefault();
}
});
//画验证码
function codeRender() {
//进来就清空验证码框的样式
svgEle.innerHTML = "";
let clientWidth = svgEle.clientWidth;
let clientHeight = svgEle.clientHeight;
//创建文档碎片
let docFra = document.createDocumentFragment();
//添加线条节点到svg节点中
let lines = createLineNode(5, 5, clientHeight, clientWidth, docFra);
svgEle.appendChild(lines);
//添加文本节点到svg节点中
let texts = createTextNode(5, clientWidth, docFra);
svgEle.appendChild(texts[0]);
//给svg标签加一个自定义属性
svgEle.dataset.str = texts[1];
}
codeRender();
//随机字母和数字
function createTextNode(num, clientWidth, docFra) {
//获取字符水平方向可以移动的距离
let maxX = parseInt(clientWidth / num);
console.log(maxX);
let str = ``;
for (let i = 0; i < num; i++) {
let textNode = document.createElementNS("http://www.w3.org/2000/svg", "text");
//获取字符
let char = getChar();
//不区分大小写
//用str拼接所有的字符,为了方便登录时进行验证
str += char;
let re = /^[a-z]$/img;
//判断字符是否为字母,且会随机变大写字母
//test方法查找:在char里面查找re;返回Boolean值,满足返回true,不满足返回false
//getRandom(0, 1):意思是让字母进来了随机成为0或者1,因为0会直接隐式转换为false就进入不了这个判断,
//所以只有当它随机为1时,才会进入if,并转换为大写字母。
if (re.test(char) && getRandom(0, 1)) {
//设置字母为大写字母
char = char.toUpperCase();
}
//把字符添加到节点中
textNode.innerHTML = char;
//设置字符的基线位置
console.log(maxX * i);
console.log(maxX * (i + 1) - 30);
textNode.setAttribute("x", getRandom(maxX * i, Math.abs(maxX * (i + 1) - 30)));
textNode.setAttribute("y", 30);
textNode.style.fontSize = 30 + "px";
textNode.style.transform = `rotate(${getRandom(0, 5)}deg)`;
//线条的颜色样式
textNode.style.fill = `rgba(${getRandom(0, 255)},${getRandom(0, 255)},${getRandom(0, 255)},1)`;
docFra.appendChild(textNode);
}
return [docFra, str];
}
//字符组
function getChar() {
let str = `0123456789abcdefghijklmnopqrstuvwxyz`;
return str[getRandom(0, str.length - 1)];
}
//随机线条
function createLineNode(num, lineWidth, clientHeight, clientWidth, docFra) {
for (let i = 0; i < num; i++) {
//添加线条
let line = document.createElementNS("http://www.w3.org/2000/svg", "line");
//起始坐标和终止坐标
line.setAttribute("x1", getRandom(0, clientWidth));
line.setAttribute("y1", getRandom(0, clientHeight));
line.setAttribute("x2", getRandom(0, clientWidth));
line.setAttribute("y2", getRandom(0, clientHeight));
line.style.stroke = `rgba(${getRandom(0, 255)},${getRandom(0, 255)},${getRandom(0, 255)},${getRandom(0, 10) / 10})`;
line.style.strokeWidth = getRandom(0, lineWidth);
//把线条添加到文档碎片中去
docFra.appendChild(line);
}
//返回这个文档碎片
return docFra;
}
//刷新文本
shuaxin.addEventListener("click", function () {
//点击刷新文本,重新渲染
codeRender();
});
//获取随机数
function getRandom(min, max = 0) {
if (min > max) {
[min, max] = [max, min];
}
return parseInt(Math.random() * (max - min + 1)) + min;
}