HTML
页面结构(index.html)
1. 流星雨动态背景
2. 主体界面(包含登录和注册表单)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="./css/login.css">
<link rel="stylesheet" href="./font/iconfont.css">
<link rel="icon" href="./src/images/capybara.png">
<title>施霁の小屋</title>
</head>
<body>
<!-- 绘制流星雨 -->
<div class="meteor">
<canvas id="canvas"></canvas>
</div>
<!-- 主体界面 -->
<div class="box">
<!-- 登录 -->
<form action="" method="post">
<div class="login-form">
<dotlottie-player class='cat' src="https://lottie.host/a3033571-ac02-4729-a4d9-d26fb88daa07/HPJ1ubBluP.lottie" background="transparent" speed="1" direction="1" playMode="normal" loop autoplay></dotlottie-player>
<div class="pre-box">
<h1>WELCOME</h1>
<div class="img-box">
<img src="./src/images/boy.jpg" alt="user">
</div>
</div>
<div class="title-box">
<dotlottie-player src="https://lottie.host/e7669feb-3952-4f0f-aa68-68e9f217f9cc/ez4KCGLiEu.json" background="transparent" speed="1" style="width: 0.7rem; height: 0.7rem" direction="1" playMode="normal" loop autoplay></dotlottie-player>
<h1>Login</h1>
</div>
<div class="input-box">
<input type="text" id="username" name="username" placeholder="Username" required="required">
<input type="password" id="password" name="password" placeholder="Password" required="required">
</div>
<!-- <p class="login-error"></p> -->
<div class="btn-box">
<button type="submit" class="login" id="log">登 录</button>
</div>
<p class="click-msg" onclick="mySwitch()">没有账号?去注册</p>
</div>
</form>
<!-- 注册 -->
<form action="" method="post">
<div class="register-form">
<div class="title-box">
<dotlottie-player src="https://lottie.host/772658ce-16ee-413d-96fc-b485d7ccae05/SshfRp85XJ.json" background speed="1" style="width: 0.7rem; height: 0.7rem" direction="1" playMode="normal" loop autoplay></dotlottie-player>
<h1>Register</h1>
</div>
<div class="input-box">
<input type="text" id="username_1" name="username_1" placeholder="Username" required="required">
<input type="password" id="password_1" name="password_1" placeholder="Password" required="required">
<input type="email" id="email_1" name="email_1" placeholder="Email" required="required">
</div>
<!-- <p class="register-error"></p> -->
<div class="btn-box">
<button type="submit" class="register" id="rgs">注 册</button>
</div>
<p class="click-msg" onclick="mySwitch()">已有账号?去登录</p>
</div>
</form>
</div>
<!-- 设置遮盖移动效果 -->
<script src="./js/cover.js"></script>
<!-- 登录注册功能 -->
<script src="./js/Login.js"></script>
<script src="./js/register.js"></script>
<!-- 绘制流星雨 -->
<script src="./js/meteor.js"></script>
<script src="./js/jquery.js"></script>
<!-- 设置自适应效果 -->
<script src="./js/flexible.js"></script>
<!-- Lottie动画 -->
<script src="https://unpkg.com/@dotlottie/player-component@latest/dist/dotlottie-player.mjs" type="module"></script>
</body>
</html>
CSS
表单结构美化(login.css),部分动画依靠Lottie的调用
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
input {
outline: none;
}
html,
body {
height: 100%;
}
body {
display: flex;
background: url(../src/images/your-name.jpg) no-repeat top fixed;
overflow: hidden;
background-size: cover;
}
.meteor {
width: 100%;
height: 100%;
position: absolute;
z-index: -1;
}
.meteor .canvas {
filter: drop-shadow(0 0 1px white);
}
@font-face {
font-family: "SNAP";
src: url(../font/fonts/SNAP.TTF);
}
.title-box h1 {
font-family: "SNAP";
color: #ffffff;
}
/* 抖动画面 */
@keyframes jitter {
0%,
100% {
/* 动画开始和结束时,元素保持原始状态 */
transform: rotate(0deg);
}
25% {
/* 动画的1/4处,元素向右旋转一个小角度 */
transform: rotate(10deg);
}
50% {
transform: rotate(5deg);
}
75% {
/* 动画的3/4处,元素开始向左旋转 */
transform: rotate(-5deg);
}
}
.box {
width: 8.3799rem;
height: 5.3073rem;
position: relative;
display: flex;
margin: auto;
border-radius: .1397rem;
border: .0279rem;
box-shadow: 5px 4px 3px rgba(0, 0, 0, 0.1);
}
.pre-box {
position: absolute;
width: 4.1899rem;
height: 100%;
top: 0;
left: 0;
border-radius: .1117rem;
box-shadow: 5px 4px 3px rgba(0, 0, 0, 0.1);
background: linear-gradient(#8de7f7, #87a5e8);
transition: 0.5s ease-in-out;
z-index: 1;
}
.pre-box h1 {
margin-top: .419rem;
color: white;
letter-spacing: .0279rem;
text-align: center;
font-size: .6285rem;
text-shadow: 5px 4px 3px rgba(0, 0, 0, 0.1);
}
.pre-box h1:hover {
cursor: pointer;
text-shadow: 5px 4px 3px rgba(9, 5, 230, 0.3);
}
.pre-box .img-box {
width: 2.7933rem;
height: 2.7933rem;
margin: .2793rem auto;
text-align: center;
}
.pre-box .img-box img {
width: 80%;
height: 80%;
border-radius: 50%;
margin-top: 30px;
box-shadow: 5px 4px 3px rgba(0, 0, 0, 0.1);
}
.pre-box .img-box img:hover {
animation: jitter 0.3s ease-in-out;
}
form {
flex: 1;
height: 100%;
}
.login-form,
.register-form {
position: relative;
height: 100%;
}
.title-box {
display: flex;
justify-self: center;
align-items: center;
flex-direction: column;
height: 1.3966rem;
line-height: 0.35rem;
}
.title-box h1 {
text-align: center;
font-size: .6285rem;
}
.input-box {
display: flex;
flex-direction: column;
align-items: center;
}
.input-box input {
width: 70%;
height: .419rem;
margin: .1397rem;
padding: .0698rem .0698rem .0698rem .3911rem;
font-size: .2235rem;
border: 1px solid #b0cfe9;
border-radius: 3px;
background-repeat: no-repeat;
background-size: .2235rem;
background-position: 5px center;
}
input[type="text"] {
background-image: url(../src/images/user.png);
}
input[type="password"] {
background-image: url(../src/images/pwd.png);
}
input[type="email"] {
background-image: url(../src/images/email.png);
}
/* .login-error,
.register-error {
height: .419rem;
padding: .0698rem auto;
margin-top: 10px;
color: #99eef7;
text-align: center;
font-weight: bold;
} */
.btn-box {
position: absolute;
bottom: 30px;
left: 50%;
transform: translateX(-50%);
display: flex;
justify-content: center;
}
.btn-box button {
border: none;
width: .838rem;
height: .419rem;
border-radius: .0419rem;
margin: .1397rem;
font-size: .2235rem;
background-color: #69b3f0;
color: white;
}
.btn-box button:hover {
cursor: pointer;
opacity: 0.8;
}
.click-msg {
position: absolute;
bottom: 10px;
left: 25%;
text-align: center;
color: #69b3f0;
font-size: .2514rem;
}
.click-msg:hover {
cursor: pointer;
color: #99eef7;
}
.cat {
position: absolute;
width: 40px;
height: 40px;
bottom: 40px;
left: 50%;
transform: translate(-50%);
}
JS
控制代码
1. 流星雨控制(meteor.js)(注意,流星雨需要jquery,需要下载到本地或者通过链接调用code.jquery.com/jquery-3.7.1.min.js,这个链接内容是源码,复制到本地js文件即可)
let canvas = document.querySelector("#canvas")
/** @type {CanvasRenderingContext2D} */
let ctx = canvas.getContext("2d")
canvas.width = window.innerWidth
canvas.height = window.innerHeight
let meteors = []
let allstar = 40
function init() {
for (let i = 0; i < allstar; i++){
newmeteor();
}
}
function resizeCanvas() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
function newmeteor() {
meteors.push(
{
lines:[{
x: parseInt(Math.random() * canvas.width),
y: parseInt(Math.random() * canvas.height * 0.7)
}],
life: parseInt(Math.random() * 100 + 100),
age: 0
}
)
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height)
var flag = false
for(let i = 0; i < meteors.length; i++){
meteor = meteors[i]
lines = meteor.lines
flag = !flag
for(let j = 0; j < lines.length; j++){
ctx.fillStyle = `rgba(255, 255, 255, ${j / lines.length})`
ctx.fillRect(lines[j].x, lines[j].y, 1, 1)
}
ctx.fillStyle = 'yellow'
// 流星头部
let head = lines[lines.length - 1]
ctx.fillRect(head.x, head.y, 1, 1)
ctx.fillRect(head.x - 1, head.y, 1, 1)
ctx.fillRect(head.x + 1, head.y, 1, 1)
ctx.fillRect(head.x, head.y - 1, 1, 1)
ctx.fillRect(head.x, head.y + 1, 1, 1)
if(meteor.age <= meteor.life / 2){
lines.push(
{
x: head.x - 1,
y: head.y + 0.51
}
)
}
else{
lines.shift()
}
meteor.age++
if(meteor.age >= meteor.life){
meteors.splice(i, 1)
newmeteor()
}
}
}
// function setup() {
// init();
// window.addEventListener('resize', resizeCanvas);
// setInterval(draw, 12);
// }
// setup();
init();
setInterval(draw, 12);
2. 登录表单动画(cover.js)
let flag = true;
const mySwitch = () => {
if(flag) {
$(".pre-box").css("transform", "translateX(100%)");
$(".pre-box").css("background", "linear-gradient(rgb(131, 184, 204), rgb(18, 48, 138))");
$(".img-box img").attr("src", "./src/images/girl.jpg");
}
else {
$(".pre-box").css("transform", "translateX(0%)");
$(".pre-box").css("background", "linear-gradient(rgb(141, 231, 247), rgb(135, 165, 232))");
$(".img-box img").attr("src", "./src/images/boy.jpg");
}
flag = !flag;
};
3. 页面自适应(flexible.js)
(function flexible(window, document) {
var docEl = document.documentElement;
var dpr = window.devicePixelRatio || 1;
// adjust body font size
function setBodyFontSize() {
if (document.body) {
document.body.style.fontSize = 12 * dpr + "px";
} else {
document.addEventListener("DOMContentLoaded", setBodyFontSize);
}
}
setBodyFontSize();
// set 1rem = viewWidth / 10
function setRemUnit() {
var rem = docEl.clientWidth / 20;
docEl.style.fontSize = rem + "px";
}
setRemUnit();
// reset rem unit on page resize
window.addEventListener("resize", setRemUnit);
window.addEventListener("pageshow", function(e) {
if (e.persisted) {
setRemUnit();
}
});
// detect 0.5px supports
if (dpr >= 2) {
var fakeBody = document.createElement("body");
var testElement = document.createElement("div");
testElement.style.border = ".5px solid transparent";
fakeBody.appendChild(testElement);
docEl.appendChild(fakeBody);
if (testElement.offsetHeight === 1) {
docEl.classList.add("hairlines");
}
docEl.removeChild(fakeBody);
}
})(window, document);
4. 登录控制(Login.js)
document.addEventListener("DOMContentLoaded", function() {
var btn = $("#log");
var errorMsg = $(".login-error"); // 获取错误消息的元素
errorMsg.css("font-size", ".2235rem"); // 设置文字大小为16像素
// 使用jQuery绑定点击事件
$(btn).click(function(e) {
e.preventDefault(); // 阻止表单的默认提交行为
var username = $("#username").val(); // 获取用户名
var password = $("#password").val(); // 获取密码
// 发送AJAX请求
$.ajax({
url: "../php/Login.php", // PHP处理文件的路径
type: "POST",
data: { // 发送的数据
"username": username,
"password": password
},
success: function(response) {
// 根据PHP返回的结果进行处理
if (response === "success") {
location.href = "../首页.html"; // 登录成功,跳转到主页
console.log("success");
errorMsg.text(''); // 清除错误消息
} else {
console.log("failed");
errorMsg.text("登录失败,请检查您的账号和密码!");
// alert("登录失败,请检查您的账号和密码!");
}
},
error: function(xhr, status, error) {
// 处理请求失败的情况
// alert("请求失败: " + error);
errorMsg.text("请求失败: " + error);
setTimeout(function() {
// 3秒后清空errorMsg的文本内容
errorMsg.text("");
}, 3000); // 3000毫秒等于3秒
}
});
});
});
5. 注册控制(register.js)
document.addEventListener("DOMContentLoaded", function() {
var btn = $("#rgs");
var errorMsg = $(".register-error"); // 获取错误消息的元素
errorMsg.css("font-size", ".2235rem"); // 设置文字大小为16像素
// 使用jQuery绑定点击事件
$(btn).click(function(e) {
e.preventDefault(); // 阻止表单的默认提交行为
var username = $("#username_1").val(); // 获取用户名
var password = $("#password_1").val(); // 获取密码
var email = $("#email_1").val(); // 获取邮箱
// 发送AJAX请求
$.ajax({
url: "../php/register.php", // PHP处理文件的路径
type: "POST",
data: { // 发送的数据
"username": username,
"password": password,
"email": email
},
success: function(response) {
// 根据PHP返回的结果进行处理
if (response.trim() === "success") {
errorMsg.text('注册成功, 去登录叭~'); // 清除错误消息
}
else if (response.trim() === "exist") {
errorMsg.text("该用户已经存在了嗷~");
}
else {
errorMsg.text("注册失败,请稍后再试~");
// alert("注册失败,请稍后再试~")
}
},
error: function(xhr, status, error) {
errorMsg.text("请求失败: " + error);
// alert("请求失败: " + error);
setTimeout(function() {
// 3秒后清空errorMsg的文本内容
errorMsg.text("");
}, 3000); // 3000毫秒等于3秒
}
});
});
});
MySQL
使用PHP连接数据库,这里是基础功能的实现,需要先创建一个数据库,基本步骤如下:
1. 进入MySQL,输入你的密码
2. 创建数据库,这里取名为web
3. 在该数据库下创建一个表user,用来存放用户登录注册信息
4. 向表中插入一些数据用于登录
5. 插入结果
6. 分配一个用户(wang)可对web中的所有表执行任何操作(可选)
PHP
(代码很简单,看注释即可)
1. 登录控制 (Login.php)
<?php
// 数据库配置信息
$host = 'localhost'; // 数据库服务器地址
$dbuser = 'wang'; // 数据库用户名
$dbpwd = 'Wxl020403.'; // 数据库密码
$dbname = 'web'; // 数据库名
// 表单提交数据
$username = trim($_POST['username']); // 去除前后空格
$password = trim($_POST['password']); // 去除前后空格
// 创建连接
$conn = new mysqli($host, $dbuser, $dbpwd, $dbname);
// 检查连接
if ($conn->connect_error) {
die("连接失败: " . $conn->connect_error);
}
else{
// $selectSQL = "SELECT * FROM user WHERE username='{$username}' AND password='{$password}'";
// $result = $conn->query($selectSQL);
// if ($result->num_rows == 1) {
// echo "success";
// }
// else{
// echo "error";
// }
// 准备SQL语句
$stmt = $conn->prepare("SELECT * FROM user WHERE username=? AND password=?");
// 绑定参数
$stmt->bind_param("ss", $username, $password);
// 执行查询
$stmt->execute();
// 获取结果
$result = $stmt->get_result();
// 检查是否有行返回
if ($result->num_rows == 1) {
echo "success";
} else {
echo "error";
}
// 关闭语句和连接
$stmt->close();
$conn->close();
}
?>
2. 注册控制(register.php)
<?php
// 数据库配置信息
$host = 'localhost'; // 数据库服务器地址
$dbuser = 'wang'; // 数据库用户名
$dbpwd = 'Wxl020403.'; // 数据库密码
$dbname = 'web'; // 数据库名
// 创建连接
$conn = new mysqli($host, $dbuser, $dbpwd, $dbname);
$username = trim($_POST['username']); // 去除前后空格
$password = trim($_POST['password']); // 去除前后空格
$email = trim($_POST['email']);
// 检查连接
if ($conn->connect_error) {
die("连接失败: " . $conn->connect_error);
}
// 使用预处理语句检查用户是否已存在
$stmt = $conn->prepare("SELECT 1 FROM user WHERE username = ?");
$stmt->bind_param("s", $username);
$stmt->execute();
$stmt->store_result();
if ($stmt->num_rows > 0) {
echo "exist";
$stmt->close();
$conn->close();
exit;
}
// 用户不存在,插入新用户,非常简单的判断
$stmt = $conn->prepare("INSERT INTO user (username, password, email) VALUES (?, ?, ?)");
$stmt->bind_param("sss", $username, $password, $email);
if($stmt->execute()) {
echo "success";
exit;
}
else{
echo "error";
exit;
}
$stmt->close();
$conn->close();
?>