长兴县文章资讯

AJAX表单验证项目实战之实时用户名检查功能

2026-03-29 16:07:01 浏览次数:0
详细信息

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

我将创建一个完整的用户注册表单,实现实时用户名可用性检查功能。这个功能会在用户输入用户名时,通过AJAX异步请求检查该用户名是否已被占用。

实现思路

创建一个用户注册表单,包含用户名、邮箱和密码字段 在用户名输入框添加事件监听,当用户输入时触发检查 通过AJAX向服务器发送异步请求,检查用户名可用性 实时显示检查结果(用户名是否可用) 添加适当的视觉反馈和用户提示

下面是完整实现:

<!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="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        }

        body {
            background: linear-gradient(135deg, #6a11cb 0%, #2575fc 100%);
            min-height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
            padding: 20px;
        }

        .container {
            width: 100%;
            max-width: 500px;
            background-color: white;
            border-radius: 12px;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
            overflow: hidden;
        }

        .header {
            background: linear-gradient(to right, #4776E6, #8E54E9);
            color: white;
            padding: 25px 30px;
            text-align: center;
        }

        .header h1 {
            font-size: 28px;
            margin-bottom: 8px;
        }

        .header p {
            opacity: 0.9;
            font-size: 15px;
        }

        .form-container {
            padding: 30px;
        }

        .form-group {
            margin-bottom: 25px;
            position: relative;
        }

        label {
            display: block;
            margin-bottom: 8px;
            font-weight: 600;
            color: #333;
            font-size: 15px;
        }

        input {
            width: 100%;
            padding: 14px 16px;
            border: 2px solid #ddd;
            border-radius: 8px;
            font-size: 16px;
            transition: all 0.3s ease;
        }

        input:focus {
            border-color: #4776E6;
            outline: none;
            box-shadow: 0 0 0 3px rgba(71, 118, 230, 0.1);
        }

        .input-icon {
            position: absolute;
            right: 16px;
            top: 40px;
            font-size: 18px;
        }

        .validation-message {
            margin-top: 6px;
            font-size: 14px;
            display: flex;
            align-items: center;
            height: 20px;
        }

        .success {
            color: #2ecc71;
        }

        .error {
            color: #e74c3c;
        }

        .loading {
            color: #3498db;
        }

        .info {
            color: #7f8c8d;
        }

        .submit-btn {
            background: linear-gradient(to right, #4776E6, #8E54E9);
            color: white;
            border: none;
            padding: 16px;
            width: 100%;
            border-radius: 8px;
            font-size: 17px;
            font-weight: 600;
            cursor: pointer;
            transition: all 0.3s ease;
            margin-top: 10px;
        }

        .submit-btn:hover {
            transform: translateY(-2px);
            box-shadow: 0 5px 15px rgba(142, 84, 233, 0.4);
        }

        .submit-btn:disabled {
            background: #cccccc;
            cursor: not-allowed;
            transform: none;
            box-shadow: none;
        }

        .demo-info {
            background-color: #f8f9fa;
            border-radius: 8px;
            padding: 15px;
            margin-top: 25px;
            border-left: 4px solid #4776E6;
        }

        .demo-info h3 {
            color: #333;
            margin-bottom: 10px;
            font-size: 16px;
        }

        .demo-info ul {
            padding-left: 20px;
            color: #555;
            font-size: 14px;
            line-height: 1.5;
        }

        .demo-info li {
            margin-bottom: 5px;
        }

        .status-indicator {
            display: inline-block;
            width: 10px;
            height: 10px;
            border-radius: 50%;
            margin-right: 8px;
        }

        .status-online {
            background-color: #2ecc71;
        }

        .status-offline {
            background-color: #e74c3c;
        }

        .server-status {
            display: flex;
            align-items: center;
            font-size: 14px;
            margin-bottom: 10px;
            color: #555;
        }

        @keyframes pulse {
            0% { opacity: 1; }
            50% { opacity: 0.5; }
            100% { opacity: 1; }
        }

        .loading-animation {
            animation: pulse 1.5s infinite;
        }

        .api-response {
            background-color: #f1f8ff;
            border-radius: 6px;
            padding: 12px;
            margin-top: 20px;
            font-family: monospace;
            font-size: 13px;
            display: none;
            border-left: 3px solid #4776E6;
        }

        .api-response h4 {
            margin-bottom: 8px;
            color: #333;
        }

        @media (max-width: 600px) {
            .container {
                max-width: 100%;
            }

            .form-container {
                padding: 25px 20px;
            }

            .header {
                padding: 20px;
            }
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <h1><i class="fas fa-user-check"></i> 实时用户名检查</h1>
            <p>在您输入时验证用户名可用性</p>
            <div class="server-status">
                <span class="status-indicator status-online" id="serverStatus"></span>
                <span id="serverStatusText">服务器连接正常</span>
            </div>
        </div>

        <div class="form-container">
            <form id="registrationForm">
                <div class="form-group">
                    <label for="username"><i class="fas fa-user"></i> 用户名</label>
                    <input 
                        type="text" 
                        id="username" 
                        name="username" 
                        placeholder="输入用户名 (至少3个字符)"
                        autocomplete="off"
                    >
                    <div class="input-icon" id="usernameIcon"></div>
                    <div class="validation-message" id="usernameMessage"></div>
                </div>

                <div class="form-group">
                    <label for="email"><i class="fas fa-envelope"></i> 电子邮箱</label>
                    <input 
                        type="email" 
                        id="email" 
                        name="email" 
                        placeholder="输入您的电子邮箱"
                    >
                </div>

                <div class="form-group">
                    <label for="password"><i class="fas fa-lock"></i> 密码</label>
                    <input 
                        type="password" 
                        id="password" 
                        name="password" 
                        placeholder="至少8个字符,包含字母和数字"
                    >
                </div>

                <button type="submit" class="submit-btn" id="submitBtn" disabled>
                    <i class="fas fa-user-plus"></i> 创建账户
                </button>
            </form>

            <div class="api-response" id="apiResponse">
                <h4>API响应信息:</h4>
                <pre id="responseContent">等待用户名检查...</pre>
            </div>

            <div class="demo-info">
                <h3><i class="fas fa-info-circle"></i> 演示说明</h3>
                <ul>
                    <li>当您在用户名输入框中键入时,系统会自动检查用户名是否可用</li>
                    <li>已占用的用户名:<code>admin</code>, <code>user123</code>, <code>testuser</code>, <code>john_doe</code></li>
                    <li>用户名必须至少3个字符,只能包含字母、数字和下划线</li>
                    <li>所有验证都在前端模拟完成,不会向真实服务器发送请求</li>
                    <li>此演示模拟了AJAX请求延迟和服务器响应</li>
                </ul>
            </div>
        </div>
    </div>

    <script>
        // 模拟已存在的用户名
        const existingUsernames = ['admin', 'user123', 'testuser', 'john_doe', 'alice', 'bob', 'charlie', 'demo'];

        // DOM元素
        const usernameInput = document.getElementById('username');
        const usernameMessage = document.getElementById('usernameMessage');
        const usernameIcon = document.getElementById('usernameIcon');
        const submitBtn = document.getElementById('submitBtn');
        const serverStatus = document.getElementById('serverStatus');
        const serverStatusText = document.getElementById('serverStatusText');
        const apiResponse = document.getElementById('apiResponse');
        const responseContent = document.getElementById('responseContent');

        // 服务器状态
        let serverOnline = true;

        // 初始化
        document.addEventListener('DOMContentLoaded', function() {
            // 添加输入事件监听
            usernameInput.addEventListener('input', handleUsernameInput);

            // 添加表单提交事件
            document.getElementById('registrationForm').addEventListener('submit', handleFormSubmit);

            // 模拟服务器状态变化
            simulateServerStatus();
        });

        // 处理用户名输入
        function handleUsernameInput() {
            const username = usernameInput.value.trim();

            // 清除之前的消息和图标
            clearValidation();

            // 如果用户名太短,不进行检查
            if (username.length < 3) {
                showInfo('用户名至少需要3个字符');
                updateSubmitButton();
                return;
            }

            // 检查用户名格式
            if (!isValidUsername(username)) {
                showError('用户名只能包含字母、数字和下划线');
                updateSubmitButton();
                return;
            }

            // 显示加载状态
            showLoading();

            // 模拟网络延迟后检查用户名
            setTimeout(() => {
                checkUsernameAvailability(username);
            }, 600);
        }

        // 检查用户名是否可用
        function checkUsernameAvailability(username) {
            // 模拟服务器连接问题
            if (!serverOnline) {
                showError('无法连接到服务器,请稍后再试');
                updateSubmitButton();
                logApiResponse({ 
                    status: 'error', 
                    message: '服务器连接失败',
                    timestamp: new Date().toISOString() 
                });
                return;
            }

            // 模拟API响应延迟
            const isAvailable = !existingUsernames.includes(username.toLowerCase());

            // 模拟随机服务器错误(10%概率)
            const randomError = Math.random() < 0.1;

            if (randomError) {
                showError('服务器错误,请稍后再试');
                logApiResponse({ 
                    status: 'error', 
                    message: '服务器内部错误',
                    timestamp: new Date().toISOString() 
                });
            } else {
                if (isAvailable) {
                    showSuccess(`用户名 "${username}" 可用`);
                    logApiResponse({ 
                        status: 'success', 
                        available: true, 
                        username: username,
                        message: '用户名可用',
                        timestamp: new Date().toISOString() 
                    });
                } else {
                    showError(`用户名 "${username}" 已被占用`);
                    logApiResponse({ 
                        status: 'success', 
                        available: false, 
                        username: username,
                        message: '用户名已被占用',
                        timestamp: new Date().toISOString() 
                    });
                }
            }

            updateSubmitButton();
        }

        // 验证用户名格式
        function isValidUsername(username) {
            const regex = /^[a-zA-Z0-9_]+$/;
            return regex.test(username);
        }

        // 显示加载状态
        function showLoading() {
            usernameMessage.textContent = '检查用户名可用性...';
            usernameMessage.className = 'validation-message loading';
            usernameIcon.innerHTML = '<i class="fas fa-spinner loading-animation"></i>';
            usernameIcon.style.color = '#3498db';
        }

        // 显示成功消息
        function showSuccess(message) {
            usernameMessage.textContent = message;
            usernameMessage.className = 'validation-message success';
            usernameIcon.innerHTML = '<i class="fas fa-check-circle"></i>';
            usernameIcon.style.color = '#2ecc71';
        }

        // 显示错误消息
        function showError(message) {
            usernameMessage.textContent = message;
            usernameMessage.className = 'validation-message error';
            usernameIcon.innerHTML = '<i class="fas fa-times-circle"></i>';
            usernameIcon.style.color = '#e74c3c';
        }

        // 显示信息消息
        function showInfo(message) {
            usernameMessage.textContent = message;
            usernameMessage.className = 'validation-message info';
            usernameIcon.innerHTML = '';
        }

        // 清除验证消息
        function clearValidation() {
            usernameMessage.textContent = '';
            usernameMessage.className = 'validation-message';
            usernameIcon.innerHTML = '';
        }

        // 更新提交按钮状态
        function updateSubmitButton() {
            const username = usernameInput.value.trim();
            const usernameIsValid = username.length >= 3 && 
                                  isValidUsername(username) && 
                                  !existingUsernames.includes(username.toLowerCase());

            submitBtn.disabled = !usernameIsValid;
        }

        // 处理表单提交
        function handleFormSubmit(e) {
            e.preventDefault();

            // 获取表单数据
            const username = usernameInput.value.trim();
            const email = document.getElementById('email').value.trim();
            const password = document.getElementById('password').value;

            // 简单验证
            if (!username || !email || !password) {
                alert('请填写所有必填字段');
                return;
            }

            // 禁用提交按钮
            submitBtn.disabled = true;
            submitBtn.innerHTML = '<i class="fas fa-spinner loading-animation"></i> 正在创建账户...';

            // 模拟注册请求
            setTimeout(() => {
                alert(`账户创建成功!\n\n用户名: ${username}\n邮箱: ${email}`);

                // 重置表单
                document.getElementById('registrationForm').reset();
                clearValidation();
                submitBtn.disabled = true;
                submitBtn.innerHTML = '<i class="fas fa-user-plus"></i> 创建账户';
                apiResponse.style.display = 'none';
            }, 1500);
        }

        // 记录API响应
        function logApiResponse(data) {
            apiResponse.style.display = 'block';
            responseContent.textContent = JSON.stringify(data, null, 2);
        }

        // 模拟服务器状态变化
        function simulateServerStatus() {
            // 每30秒随机切换服务器状态(用于演示)
            setInterval(() => {
                serverOnline = Math.random() > 0.2; // 80%时间在线

                if (serverOnline) {
                    serverStatus.className = 'status-indicator status-online';
                    serverStatusText.textContent = '服务器连接正常';
                } else {
                    serverStatus.className = 'status-indicator status-offline';
                    serverStatusText.textContent = '服务器连接失败 - 演示模式';
                }
            }, 30000);
        }

        // 模拟真实AJAX请求
        function simulateAjaxRequest(username) {
            return new Promise((resolve, reject) => {
                // 模拟网络延迟
                setTimeout(() => {
                    // 模拟随机网络错误(5%概率)
                    const networkError = Math.random() < 0.05;

                    if (networkError) {
                        reject(new Error('网络连接失败'));
                    } else {
                        const isAvailable = !existingUsernames.includes(username.toLowerCase());
                        resolve({
                            success: true,
                            available: isAvailable,
                            username: username,
                            timestamp: new Date().toISOString()
                        });
                    }
                }, 500 + Math.random() * 1000); // 500-1500ms延迟
            });
        }
    </script>
</body>
</html>

功能说明

实时用户名验证

验证逻辑

模拟服务器交互

用户体验优化

使用说明

在用户名输入框中输入用户名 系统会自动检查用户名是否可用 可用的用户名会显示绿色提示和勾选图标 已占用的用户名会显示红色提示和错误图标 只有用户名可用时,注册按钮才会启用 点击"创建账户"按钮模拟注册过程

这个实现完全在前端运行,模拟了与后端服务器的交互过程,适合学习和演示AJAX表单验证的原理。

相关推荐