当前位置: 首页 > news >正文

AJAX表单验证项目实战:实时用户名检查

项目概述

本项目实现一个注册页面的用户名实时验证功能,使用AJAX技术在用户输入时异步检查用户名是否已被占用,提供即时反馈。

技术栈

  • 前端:HTML5, CSS3, JavaScript (原生AJAX)
  • 后端:Python Flask
  • 数据存储:简单文本文件存储已注册用户名

功能需求

  1. 用户在注册表单输入用户名
  2. 输入框失去焦点或用户停止输入后自动触发检查
  3. 实时显示"用户名可用"或"用户名已被占用"提示
  4. 显示加载状态指示正在检查

项目结构

ajax-form-validation/
├── static/
│   ├── css/
│   │   └── style.css    # 样式文件
│   └── js/
│       └── script.js    # AJAX逻辑
├── templates/
│   └── index.html       # 注册表单页面
├── data/
│   └── users.txt        # 存储已注册用户名
└── app.py               # Flask后端

前端设计

HTML结构

  • 注册表单包含用户名、密码等字段
  • 用户名输入框添加事件监听
  • 提示信息区域用于显示验证结果

CSS样式

  • 输入框状态样式(正常、验证中、有效、无效)
  • 提示信息样式(成功、错误、加载中)
  • 响应式设计适配不同设备

JavaScript逻辑

  • 使用addEventListener监听输入事件
  • 实现AJAX请求函数
  • 处理服务器响应并更新UI
  • 添加防抖处理避免频繁请求

后端设计

API接口

  • GET /check-username?username=xxx 检查用户名是否存在
  • 返回JSON格式响应:{ “available”: true/false }

数据处理

  • 从users.txt读取已注册用户名
  • 检查请求的用户名是否存在
  • 返回检查结果

以下是代码:

  • index.html
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>用户注册 - AJAX表单验证示例</title><link rel="stylesheet" href="../static/css/style.css" />
</head><body><div class="container"><h1>用户注册</h1><form id="registerForm"><div class="form-group"><label for="username">用户名:</label><div class="input-group"><input type="text" id="username" name="username" required minlength="3" maxlength="20" placeholder="请输入用户名"><div id="usernameFeedback" class="feedback"></div></div><small>用户名长度为3-20个字符</small></div><div class="form-group"><label for="password">密码:</label><input type="password" id="password" name="password" required minlength="6" placeholder="请输入密码"></div><div class="form-group"><label for="email">邮箱:</label><input type="email" id="email" name="email" required placeholder="请输入邮箱"></div><button type="submit" id="submitBtn">注册</button></form></div><script src="../static/js/script.js"></script>
</body>
</html>
  • style.css
* {box-sizing: border-box;margin: 0;padding: 0;font-family: 'Arial', sans-serif;
}body {background-color: #f5f5f5;display: flex;justify-content: center;align-items: center;min-height: 100vh;padding: 20px;
}.container {background-color: white;padding: 30px;border-radius: 8px;box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);width: 100%;max-width: 400px;
}h1 {text-align: center;margin-bottom: 25px;color: #333;
}.form-group {margin-bottom: 20px;
}label {display: block;margin-bottom: 8px;color: #555;font-weight: 500;
}input {width: 100%;padding: 10px;border: 1px solid #ddd;border-radius: 4px;font-size: 16px;transition: border-color 0.3s;
}input:focus {outline: none;border-color: #4CAF50;box-shadow: 0 0 0 2px rgba(76, 175, 80, 0.2);
}.input-group {position: relative;
}.feedback {position: absolute;right: 10px;top: 50%;transform: translateY(-50%);font-size: 14px;display: none;
}.feedback.loading {color: #999;display: inline;
}.feedback.available {color: #4CAF50;display: inline;
}.feedback.unavailable {color: #F44336;display: inline;
}small {display: block;margin-top: 5px;color: #777;font-size: 12px;
}button {width: 100%;padding: 12px;background-color: #4CAF50;color: white;border: none;border-radius: 4px;font-size: 16px;cursor: pointer;transition: background-color 0.3s;
}button:hover {background-color: #45a049;
}button:disabled {background-color: #cccccc;cursor: not-allowed;
}
  • script.js
document.addEventListener('DOMContentLoaded', function() {const usernameInput = document.getElementById('username');const feedbackElement = document.getElementById('usernameFeedback');const submitBtn = document.getElementById('submitBtn');let isUsernameAvailable = false;// 防抖函数function debounce(func, delay = 500) {let timeoutId;return function(...args) {clearTimeout(timeoutId);timeoutId = setTimeout(() => func.apply(this, args), delay);};}// 检查用户名function checkUsername() {const username = usernameInput.value.trim();// 如果用户名为空,不检查if (!username) {feedbackElement.style.display = 'none';isUsernameAvailable = false;updateSubmitButton();return;}// 显示加载状态feedbackElement.textContent = '检查中...';feedbackElement.className = 'feedback loading';// 创建AJAX请求const xhr = new XMLHttpRequest();xhr.open('GET', `/check-username?username=${encodeURIComponent(username)}`, true);xhr.onload = function() {if (xhr.status === 200) {try {const response = JSON.parse(xhr.responseText);if (response.available) {feedbackElement.textContent = '用户名可用';feedbackElement.className = 'feedback available';isUsernameAvailable = true;} else {feedbackElement.textContent = '用户名已被占用';feedbackElement.className = 'feedback unavailable';isUsernameAvailable = false;}} catch (e) {feedbackElement.textContent = '检查失败,请重试';feedbackElement.className = 'feedback unavailable';isUsernameAvailable = false;}} else {feedbackElement.textContent = '服务器错误,请稍后再试';feedbackElement.className = 'feedback unavailable';isUsernameAvailable = false;}updateSubmitButton();};xhr.onerror = function() {feedbackElement.textContent = '网络错误,请检查连接';feedbackElement.className = 'feedback unavailable';isUsernameAvailable = false;updateSubmitButton();};xhr.send();}// 更新提交按钮状态function updateSubmitButton() {submitBtn.disabled = !isUsernameAvailable || !usernameInput.value.trim();}// 监听输入事件,使用防抖usernameInput.addEventListener('input', debounce(checkUsername));// 监听失焦事件usernameInput.addEventListener('blur', checkUsername);// 表单提交处理document.getElementById('registerForm').addEventListener('submit', function(e) {e.preventDefault();if (isUsernameAvailable) {// 这里可以添加表单提交逻辑alert('注册成功!');}});
});

运行结果:
data.txt文件中有admin用户名的情况下

  • 用户名存在的情况下,注册不了
    在这里插入图片描述
  • 用户名不存在的情况下,注册成功
  • 在这里插入图片描述
http://www.lryc.cn/news/609942.html

相关文章:

  • curl发送文件bodyParser无法获取请求体的问题分析
  • Stanford CS336 assignment1 | Byte-Pair Encoding (BPE) Tokenizer
  • NeoBase:一款开源、基于AI的数据库管理助手
  • 《Python 实用项目与工具制作指南》· 2.2 变量
  • Java中给List<T> 对象集合去重
  • golang的数组
  • SpringMVC 6+源码分析(三)DispatcherServlet实例化流程 2--(url 与contrller类如何进行映射)
  • 【Spring AI快速上手 (一)】ChatModel与ChatCilent构建对话
  • 小鹏汽车前端面经
  • Python+QT开发环境搭建
  • 数据从mysql迁移到postgresql
  • 纯前端导出Excel
  • MCP安全机制深度剖析:权限控制与数据保护最佳实践
  • 体验Java接入langchain4j运用大模型OpenAi
  • 学习游戏制作记录(角色属性和状态脚本)8.4
  • 多源异构信号同步采集与赛道数据融合技术解析
  • 迅为RK3568开发板OpeHarmony学习开发手册-修改调试串口波特率
  • codeBuddy IDE 使用教程
  • 零售行业线上线下融合趋势,华为云智能零售解决方案,在门店运营与电商业务中的技术应用与场景实践
  • Qt 自动无法加载数据库为空
  • SP20D120CTR碳化硅二极管详解:高性能与广泛应用
  • 最小二乘法MSE
  • 嵌入式开发学习———Linux环境下IO进程线程学习(三)
  • AtCoder Beginner Contest 416 C 题
  • 同质无向加权图:理论基础、算法演进与应用前沿
  • 张宇高数基础30讲与1000题学习笔记(第4-6章)
  • Node.js高并发接口下的事件循环卡顿问题与异步解耦优化方案
  • Lego-Loam TransformToStartIMU TransformToStart TransformToEnd的区别
  • 时序数据库如何高效处理海量数据
  • Node.js(四)之数据库与身份认证