|
|
|
|
@ -0,0 +1,507 @@
|
|
|
|
|
<?php
|
|
|
|
|
require_once("config.php"); // 数据库连接配置
|
|
|
|
|
session_start();
|
|
|
|
|
|
|
|
|
|
// 反爬机制配置
|
|
|
|
|
$antiSpamConfig = [
|
|
|
|
|
'login_attempts_limit' => 5, // 登录尝试次数限制
|
|
|
|
|
'block_time' => 15 * 60, // 封锁时间(秒)
|
|
|
|
|
'check_interval' => 60 * 60, // 检查时间窗口(秒)
|
|
|
|
|
'ip_blacklist_file' => __DIR__ . '/data/ip_blacklist.txt',
|
|
|
|
|
'login_attempts_file' => __DIR__ . '/data/login_attempts.json'
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$antiSpamDir = dirname($antiSpamConfig['login_attempts_file']);
|
|
|
|
|
if (!file_exists($antiSpamDir)) {
|
|
|
|
|
mkdir($antiSpamDir, 0777, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取客户端IP地址
|
|
|
|
|
function getClientIP() {
|
|
|
|
|
if (isset($_SERVER['HTTP_CLIENT_IP']))
|
|
|
|
|
return $_SERVER['HTTP_CLIENT_IP'];
|
|
|
|
|
if (isset($_SERVER['HTTP_X_FORWARDED_FOR']))
|
|
|
|
|
return explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'])[0];
|
|
|
|
|
return $_SERVER['REMOTE_ADDR'];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查IP是否在黑名单中
|
|
|
|
|
function isIPBlacklisted($ip, $blacklistFile) {
|
|
|
|
|
if (!file_exists($blacklistFile)) return false;
|
|
|
|
|
|
|
|
|
|
$blacklist = file($blacklistFile, FILE_IGNORE_NEW_LINES);
|
|
|
|
|
return in_array($ip, $blacklist);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 记录登录尝试
|
|
|
|
|
function logLoginAttempt($ip, $success, $config) {
|
|
|
|
|
$attempts = [];
|
|
|
|
|
$file = $config['login_attempts_file'];
|
|
|
|
|
|
|
|
|
|
// 读取现有记录
|
|
|
|
|
if (file_exists($file)) {
|
|
|
|
|
$json = file_get_contents($file);
|
|
|
|
|
$attempts = json_decode($json, true) ?: [];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 添加新记录
|
|
|
|
|
$attempts[] = [
|
|
|
|
|
'ip' => $ip,
|
|
|
|
|
'time' => time(),
|
|
|
|
|
'success' => $success
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
// 只保留指定时间窗口内的记录
|
|
|
|
|
$threshold = time() - $config['check_interval'];
|
|
|
|
|
$attempts = array_filter($attempts, function($a) use ($threshold) {
|
|
|
|
|
return $a['time'] >= $threshold;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 保存记录
|
|
|
|
|
file_put_contents($file, json_encode(array_values($attempts)));
|
|
|
|
|
|
|
|
|
|
// 如果失败次数超过限制,将IP加入黑名单
|
|
|
|
|
$ipAttempts = array_filter($attempts, function($a) use ($ip) {
|
|
|
|
|
return $a['ip'] === $ip && !$a['success'];
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (count($ipAttempts) >= $config['login_attempts_limit']) {
|
|
|
|
|
addToIPBlacklist($ip, $config['ip_blacklist_file']);
|
|
|
|
|
return true; // IP已被封锁
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 添加IP到黑名单
|
|
|
|
|
function addToIPBlacklist($ip, $blacklistFile) {
|
|
|
|
|
file_put_contents($blacklistFile, $ip . PHP_EOL, FILE_APPEND);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查并处理验证码请求
|
|
|
|
|
if (isset($_GET['get_captcha'])) {
|
|
|
|
|
// 可以添加IP请求频率检查
|
|
|
|
|
header('Content-Type: image/png');
|
|
|
|
|
include('verify.php');
|
|
|
|
|
exit;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取客户端IP
|
|
|
|
|
$clientIP = getClientIP();
|
|
|
|
|
|
|
|
|
|
// 检查IP是否被封锁
|
|
|
|
|
if (isIPBlacklisted($clientIP, $antiSpamConfig['ip_blacklist_file'])) {
|
|
|
|
|
http_response_code(403);
|
|
|
|
|
die("您的IP已被封锁,请稍后再试。");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 密码哈希加密配置(可选:设置算法参数)
|
|
|
|
|
// define('PASSWORD_COST', 12); // 默认10,数值越大越安全但性能消耗越高
|
|
|
|
|
|
|
|
|
|
if ($_SERVER["REQUEST_METHOD"] == "POST") {
|
|
|
|
|
$username = trim($_POST["username"]); // 去除首尾空格
|
|
|
|
|
$plainPassword = trim($_POST["pwd"]); // 原始密码(不存储)
|
|
|
|
|
$code = trim($_POST["code"]);
|
|
|
|
|
|
|
|
|
|
// 输入验证:非空检查
|
|
|
|
|
if (empty($username) || empty($plainPassword) || empty($code)) {
|
|
|
|
|
logLoginAttempt($clientIP, false, $antiSpamConfig);
|
|
|
|
|
echo "<script>alert('用户名、密码或验证码不可为空!'); location.href='login.php';</script>";
|
|
|
|
|
exit();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 验证码验证(区分大小写需调整strtolower)
|
|
|
|
|
if (strtolower($_SESSION["code"]) !== strtolower($code)) {
|
|
|
|
|
logLoginAttempt($clientIP, false, $antiSpamConfig);
|
|
|
|
|
echo "<script>alert('验证码错误!请重新登录!'); location.href='login.php';</script>";
|
|
|
|
|
exit();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 数据库查询:获取用户哈希密码
|
|
|
|
|
$stmt = $connect->prepare("SELECT id, username, password FROM librarian WHERE username=?");
|
|
|
|
|
$stmt->bind_param("s", $username);
|
|
|
|
|
$stmt->execute();
|
|
|
|
|
$result = $stmt->get_result();
|
|
|
|
|
|
|
|
|
|
if ($user = $result->fetch_assoc()) {
|
|
|
|
|
// 验证密码哈希
|
|
|
|
|
if (password_verify($plainPassword, $user["password"])) {
|
|
|
|
|
// 密码正确,更新会话并跳转
|
|
|
|
|
logLoginAttempt($clientIP, true, $antiSpamConfig);
|
|
|
|
|
|
|
|
|
|
$_SESSION["user_id"] = $user["id"];
|
|
|
|
|
$_SESSION["username"] = $user["username"];
|
|
|
|
|
$_SESSION["login_time"] = time(); // 记录登录时间(可选)
|
|
|
|
|
|
|
|
|
|
// 自动更新哈希版本(可选:若使用旧算法)
|
|
|
|
|
// if (password_needs_rehash($user["password"], PASSWORD_DEFAULT, ['cost' => PASSWORD_COST])) {
|
|
|
|
|
// $newHashedPassword = password_hash($plainPassword, PASSWORD_DEFAULT, ['cost' => PASSWORD_COST]);
|
|
|
|
|
// $updateStmt = $connect->prepare("UPDATE librarian SET password=? WHERE id=?");
|
|
|
|
|
// $updateStmt->bind_param("si", $newHashedPassword, $user["id"]);
|
|
|
|
|
// $updateStmt->execute();
|
|
|
|
|
// $updateStmt->close();
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
header("Location: admin_index.php");
|
|
|
|
|
exit();
|
|
|
|
|
} else {
|
|
|
|
|
// 密码错误
|
|
|
|
|
logLoginAttempt($clientIP, false, $antiSpamConfig);
|
|
|
|
|
$stmt->close();
|
|
|
|
|
echo "<script>alert('用户名或密码错误!请重新登录!'); location.href='login.php';</script>";
|
|
|
|
|
exit();
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// 用户不存在
|
|
|
|
|
logLoginAttempt($clientIP, false, $antiSpamConfig);
|
|
|
|
|
$stmt->close();
|
|
|
|
|
echo "<script>alert('用户名或密码错误!请重新登录!'); location.href='login.php';</script>";
|
|
|
|
|
exit();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$stmt->close();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 退出登录逻辑
|
|
|
|
|
if (isset($_GET['tj']) && $_GET['tj'] == 'out') {
|
|
|
|
|
session_destroy();
|
|
|
|
|
header('location: login.php');
|
|
|
|
|
exit;
|
|
|
|
|
}
|
|
|
|
|
?>
|
|
|
|
|
<!DOCTYPE html>
|
|
|
|
|
<html>
|
|
|
|
|
<head>
|
|
|
|
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
|
|
|
|
<link rel="shortcut icon" href="icon/favicon.ico" type="image/x-icon">
|
|
|
|
|
<title>图书后台管理系统登录功能</title>
|
|
|
|
|
<style>
|
|
|
|
|
.bg-container {
|
|
|
|
|
position: fixed;
|
|
|
|
|
top: 0;
|
|
|
|
|
left: 0;
|
|
|
|
|
width: 100vw;
|
|
|
|
|
height: 100vh;
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
z-index: -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.bg-item {
|
|
|
|
|
position: absolute;
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 100%;
|
|
|
|
|
object-fit: cover;
|
|
|
|
|
opacity: 0;
|
|
|
|
|
transition: opacity 1s ease-in-out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.bg-item.active {
|
|
|
|
|
opacity: 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
body * {
|
|
|
|
|
-webkit-user-select: none;
|
|
|
|
|
-moz-user-select: none;
|
|
|
|
|
-ms-user-select: none;
|
|
|
|
|
user-select: none;
|
|
|
|
|
-webkit-user-drag: none;
|
|
|
|
|
-moz-user-drag: none;
|
|
|
|
|
-ms-user-drag: none;
|
|
|
|
|
user-drag: none;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
input, textarea {
|
|
|
|
|
-webkit-user-select: auto !important;
|
|
|
|
|
-moz-user-select: auto !important;
|
|
|
|
|
-ms-user-select: auto !important;
|
|
|
|
|
user-select: auto !important;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.copyright {
|
|
|
|
|
position: fixed;
|
|
|
|
|
bottom: 15px;
|
|
|
|
|
left: 50%;
|
|
|
|
|
transform: translateX(-50%);
|
|
|
|
|
color: rgba(255,255,255,0.6);
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
z-index: 100;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@keyframes fadeIn { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } }
|
|
|
|
|
@keyframes slideInLeft { from { opacity: 0; transform: translateX(-50px); } to { opacity: 1; transform: translateX(0); } }
|
|
|
|
|
@keyframes slideInRight { from { opacity: 0; transform: translateX(50px); } to { opacity: 1; transform: translateX(0); } }
|
|
|
|
|
@keyframes shake { 0%,100% { transform: translateX(0); } 25% { transform: translateX(-5px); } 75% { transform: translateX(5px); } }
|
|
|
|
|
|
|
|
|
|
body {
|
|
|
|
|
margin: 0;
|
|
|
|
|
padding: 0;
|
|
|
|
|
font-family: 'Microsoft YaHei', sans-serif;
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
align-items: center;
|
|
|
|
|
position: relative;
|
|
|
|
|
min-height: 100vh;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.big_box {
|
|
|
|
|
width: 960px;
|
|
|
|
|
height: 500px;
|
|
|
|
|
margin: auto;
|
|
|
|
|
background: rgba(255, 255, 255, 0.38);
|
|
|
|
|
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
border-radius: 20px 0 0 20px;
|
|
|
|
|
backdrop-filter: blur(5px);
|
|
|
|
|
display: flex;
|
|
|
|
|
position: relative;
|
|
|
|
|
z-index: 10;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.left_box {
|
|
|
|
|
width: 50%;
|
|
|
|
|
height: 100%;
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
clip-path: ellipse(100% 100% at 0% 50%);
|
|
|
|
|
}
|
|
|
|
|
.left_box img {
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 100%;
|
|
|
|
|
object-fit: cover;
|
|
|
|
|
}
|
|
|
|
|
.right_box {
|
|
|
|
|
width: 50%;
|
|
|
|
|
text-align: center;
|
|
|
|
|
animation: slideInRight 0.8s ease-out;
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
padding: 40px;
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
background: transparent;
|
|
|
|
|
}
|
|
|
|
|
table {
|
|
|
|
|
margin: auto;
|
|
|
|
|
animation: fadeIn 1s ease-out;
|
|
|
|
|
width: 100%;
|
|
|
|
|
max-width: 320px;
|
|
|
|
|
}
|
|
|
|
|
h2 {
|
|
|
|
|
margin-top: 0;
|
|
|
|
|
color: #333;
|
|
|
|
|
animation: fadeIn 0.8s ease-out;
|
|
|
|
|
margin-bottom: 30px;
|
|
|
|
|
}
|
|
|
|
|
.iput {
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 40px;
|
|
|
|
|
border: 1px solid #ddd;
|
|
|
|
|
border-radius: 6px;
|
|
|
|
|
padding: 0 15px;
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
background-color: rgba(255, 255, 255, 0.9);
|
|
|
|
|
}
|
|
|
|
|
.iput:focus {
|
|
|
|
|
border-color: #4a90e2;
|
|
|
|
|
box-shadow: 0 0 8px rgba(74, 144, 226, 0.2);
|
|
|
|
|
outline: none;
|
|
|
|
|
}
|
|
|
|
|
.iput1, .iut2 {
|
|
|
|
|
width: 120px;
|
|
|
|
|
height: 45px;
|
|
|
|
|
font-size: 15px;
|
|
|
|
|
margin: 0 10px;
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
transition: all 0.3s;
|
|
|
|
|
}
|
|
|
|
|
.iput1 {
|
|
|
|
|
background-color: #4a90e2;
|
|
|
|
|
color: white;
|
|
|
|
|
border: none;
|
|
|
|
|
border-radius: 6px;
|
|
|
|
|
}
|
|
|
|
|
.iput1:hover {
|
|
|
|
|
background-color: #3a7bc8;
|
|
|
|
|
}
|
|
|
|
|
.iut2 {
|
|
|
|
|
background-color: #f5f5f5;
|
|
|
|
|
color: #333;
|
|
|
|
|
border: 1px solid #ddd;
|
|
|
|
|
border-radius: 6px;
|
|
|
|
|
}
|
|
|
|
|
.iut2:hover {
|
|
|
|
|
background-color: #e0e0e0;
|
|
|
|
|
}
|
|
|
|
|
.big_box.shake {
|
|
|
|
|
animation: shake 0.3s ease-in-out forwards;
|
|
|
|
|
}
|
|
|
|
|
tr {
|
|
|
|
|
height: 60px;
|
|
|
|
|
}
|
|
|
|
|
.verify-container {
|
|
|
|
|
position: relative;
|
|
|
|
|
}
|
|
|
|
|
.verify-code {
|
|
|
|
|
position: absolute;
|
|
|
|
|
right: 5px;
|
|
|
|
|
top: 50%;
|
|
|
|
|
transform: translateY(-50%);
|
|
|
|
|
height: 30px;
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.core-value {
|
|
|
|
|
position: absolute;
|
|
|
|
|
pointer-events: none;
|
|
|
|
|
font-size: 18px;
|
|
|
|
|
font-family: '微软雅黑';
|
|
|
|
|
color: #FF0000;
|
|
|
|
|
user-select: none;
|
|
|
|
|
z-index: 999;
|
|
|
|
|
transform: scale(0.1);
|
|
|
|
|
transition: transform 0.3s ease-out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.core-value.active {
|
|
|
|
|
transform: scale(1);
|
|
|
|
|
}
|
|
|
|
|
</style>
|
|
|
|
|
</head>
|
|
|
|
|
<body oncontextmenu="return false;" ondragstart="return false;" onselectstart="return false;">
|
|
|
|
|
<div class="bg-container" id="bgContainer">
|
|
|
|
|
<img src="image/2.png" alt="背景1" class="bg-item">
|
|
|
|
|
<img src="image/4.png" alt="背景2" class="bg-item active">
|
|
|
|
|
<img src="image/5.png" alt="背景3" class="bg-item">
|
|
|
|
|
<img src="image/1.jpg" alt="背景4" class="bg-item">
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="big_box">
|
|
|
|
|
<div class="left_box"><img src="image/ysjf.jpg" draggable="false"></div>
|
|
|
|
|
<div class="right_box">
|
|
|
|
|
<h2>图书管理后台管理中心</h2>
|
|
|
|
|
<form method="post" action="" onsubmit="return check()">
|
|
|
|
|
<table>
|
|
|
|
|
<tr>
|
|
|
|
|
<td>
|
|
|
|
|
<input type="text" name="username" class="iput" placeholder="请输入用户名">
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
<tr>
|
|
|
|
|
<td>
|
|
|
|
|
<input type="password" name="pwd" class="iput" placeholder="请输入密码">
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
<tr>
|
|
|
|
|
<td>
|
|
|
|
|
<div class="verify-container">
|
|
|
|
|
<input type="text" name="code" class="iput" placeholder="请输入验证码">
|
|
|
|
|
<img src="verify.php" alt="验证码" class="verify-code" onclick="this.src='verify.php?'+Math.random()" draggable="false">
|
|
|
|
|
</div>
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
<tr>
|
|
|
|
|
<td align="center">
|
|
|
|
|
<input type="submit" name="login" value="登录" class="iput1">
|
|
|
|
|
<input type="button" name="register" value="注册" class="iut2" onclick="window.location.href='register.php'">
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
</table>
|
|
|
|
|
</form>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="copyright">
|
|
|
|
|
@2025-05.22 由唯出品/gitee/github/4230603094
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
const bgImages = document.querySelectorAll('.bg-item');
|
|
|
|
|
let currentIndex = 0;
|
|
|
|
|
|
|
|
|
|
function switchBackground() {
|
|
|
|
|
bgImages[currentIndex].classList.remove('active');
|
|
|
|
|
currentIndex = (currentIndex + 1) % bgImages.length;
|
|
|
|
|
bgImages[currentIndex].classList.add('active');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
|
|
|
setInterval(switchBackground, 5000);
|
|
|
|
|
|
|
|
|
|
// 完全禁止右键菜单
|
|
|
|
|
document.addEventListener('contextmenu', function(e) {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 禁止选择文本
|
|
|
|
|
document.addEventListener('selectstart', function(e) {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 禁止拖拽
|
|
|
|
|
document.addEventListener('dragstart', function(e) {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 输入框聚焦效果
|
|
|
|
|
const inputs = document.querySelectorAll('.iput');
|
|
|
|
|
inputs.forEach(input => {
|
|
|
|
|
input.addEventListener('focus', function() {
|
|
|
|
|
this.style.boxShadow = '0 0 8px rgba(74, 144, 226, 0.3)';
|
|
|
|
|
});
|
|
|
|
|
input.addEventListener('blur', function() {
|
|
|
|
|
this.style.boxShadow = '';
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 确保所有图片不可拖拽
|
|
|
|
|
document.querySelectorAll('img').forEach(img => {
|
|
|
|
|
img.draggable = false;
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
function check() {
|
|
|
|
|
const username = document.querySelector('input[name="username"]').value;
|
|
|
|
|
const password = document.querySelector('input[name="pwd"]').value;
|
|
|
|
|
const code = document.querySelector('input[name="code"]').value;
|
|
|
|
|
|
|
|
|
|
if (!username || !password || !code) {
|
|
|
|
|
alert('用户名、密码和验证码不可为空!');
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const coreValues = [
|
|
|
|
|
'富强', '民主', '文明', '和谐',
|
|
|
|
|
'自由', '平等', '公正', '法治',
|
|
|
|
|
'爱国', '敬业', '诚信', '友善'
|
|
|
|
|
].flatMap(word => [word, word]);
|
|
|
|
|
|
|
|
|
|
document.addEventListener('click', (e) => {
|
|
|
|
|
if (e.button !== 0) return;
|
|
|
|
|
|
|
|
|
|
const x = e.clientX;
|
|
|
|
|
const y = e.clientY;
|
|
|
|
|
const randomIndex = Math.floor(Math.random() * coreValues.length);
|
|
|
|
|
const valueText = coreValues[randomIndex];
|
|
|
|
|
|
|
|
|
|
const span = document.createElement('span');
|
|
|
|
|
span.className = 'core-value';
|
|
|
|
|
span.textContent = valueText;
|
|
|
|
|
span.style.left = `${x}px`;
|
|
|
|
|
span.style.top = `${y}px`;
|
|
|
|
|
|
|
|
|
|
span.classList.add('active');
|
|
|
|
|
document.body.appendChild(span);
|
|
|
|
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
span.remove();
|
|
|
|
|
}, 1000);
|
|
|
|
|
});
|
|
|
|
|
</script>
|
|
|
|
|
</body>
|
|
|
|
|
</html>
|