1. HTML 结构:创建登录表单。
  2. CSS 样式:美化页面,使其看起来专业和现代。
  3. JavaScript 交互:实现表单验证、登录逻辑和页面反馈。

最终效果预览

这是一个我们最终要实现的效果,它包含了:

javascript做网页登录页面
(图片来源网络,侵删)
  • 现代化的UI设计
  • 客户端表单验证(用户名/密码非空)
  • 模拟的后端登录验证(正确的用户名是 admin,密码是 password123
  • 登录成功后跳转到欢迎页面
  • 登录失败后显示错误提示
  • 加载状态指示器

第 1 步:HTML 结构 (index.html)

我们创建一个基本的 HTML 文件,包含登录表单,表单中需要有用户名、密码输入框,以及登录按钮。

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">登录页面</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div class="login-container">
        <form id="loginForm" class="login-form">
            <h2>用户登录</h2>
            <!-- 错误提示区域 -->
            <div id="errorMessage" class="error-message"></div>
            <div class="form-group">
                <label for="username">用户名</label>
                <input type="text" id="username" name="username" placeholder="请输入用户名" required>
            </div>
            <div class="form-group">
                <label for="password">密码</label>
                <input type="password" id="password" name="password" placeholder="请输入密码" required>
            </div>
            <button type="submit" id="loginButton" class="login-button">
                <span id="buttonText">登录</span>
                <span id="loadingSpinner" class="spinner" style="display: none;"></span>
            </button>
        </form>
    </div>
    <!-- 用于登录后跳转的欢迎页面 (初始隐藏) -->
    <div id="welcomePage" class="welcome-page" style="display: none;">
        <h1>欢迎回来, <span id="welcomeUsername"></span>!</h1>
        <p>登录成功。</p>
        <button onclick="logout()">退出登录</button>
    </div>
    <script src="script.js"></script>
</body>
</html>

第 2 步:CSS 样式 (style.css)

我们用 CSS 来美化这个登录页面,使其更具吸引力。

/* 全局样式和变量 */
:root {
    --primary-color: #4a90e2;
    --error-color: #e74c3c;
    --success-color: #2ecc71;
    --text-color: #333;
    --light-gray: #ecf0f1;
    --border-color: #bdc3c7;
}
body {
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    background-color: #f4f7f6;
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100vh;
    margin: 0;
    color: var(--text-color);
}
/* 登录容器 */
.login-container {
    background-color: white;
    padding: 40px;
    border-radius: 10px;
    box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
    width: 100%;
    max-width: 400px;
}
/* 表单样式 */
.login-form h2 {
    text-align: center;
    margin-bottom: 25px;
    color: var(--primary-color);
}
.form-group {
    margin-bottom: 20px;
}
.form-group label {
    display: block;
    margin-bottom: 8px;
    font-weight: 600;
}
.form-group input {
    width: 100%;
    padding: 12px;
    border: 1px solid var(--border-color);
    border-radius: 5px;
    box-sizing: border-box; /* 确保padding不会影响宽度 */
    font-size: 16px;
    transition: border-color 0.3s;
}
.form-group input:focus {
    outline: none;
    border-color: var(--primary-color);
}
/* 错误信息样式 */
.error-message {
    color: var(--error-color);
    text-align: center;
    margin-bottom: 20px;
    font-size: 14px;
    height: 20px; /* 固定高度,防止页面跳动 */
}
/* 登录按钮样式 */
.login-button {
    width: 100%;
    padding: 12px;
    background-color: var(--primary-color);
    border: none;
    border-radius: 5px;
    color: white;
    font-size: 16px;
    font-weight: bold;
    cursor: pointer;
    position: relative; /* 用于定位加载动画 */
    transition: background-color 0.3s;
}
.login-button:hover {
    background-color: #357abd;
}
/* 加载动画 (spinner) */
.spinner {
    border: 2px solid #f3f3f3;
    border-top: 2px solid white;
    border-radius: 50%;
    width: 16px;
    height: 16px;
    animation: spin 1s linear infinite;
    position: absolute;
    right: 15px;
    top: 50%;
    transform: translateY(-50%);
}
@keyframes spin {
    0% { transform: translateY(-50%) rotate(0deg); }
    100% { transform: translateY(-50%) rotate(360deg); }
}
/* 欢迎页面样式 */
.welcome-page {
    text-align: center;
    background-color: white;
    padding: 40px;
    border-radius: 10px;
    box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
}
.welcome-page h1 {
    color: var(--success-color);
}
.welcome-page button {
    margin-top: 20px;
    padding: 10px 20px;
    border: none;
    border-radius: 5px;
    background-color: var(--primary-color);
    color: white;
    cursor: pointer;
}

第 3 步:JavaScript 交互 (script.js)

这是核心部分,我们将在这里实现所有的登录逻辑。

// 获取DOM元素
const loginForm = document.getElementById('loginForm');
const usernameInput = document.getElementById('username');
const passwordInput = document.getElementById('password');
const loginButton = document.getElementById('loginButton');
const buttonText = document.getElementById('buttonText');
const loadingSpinner = document.getElementById('loadingSpinner');
const errorMessage = document.getElementById('errorMessage');
const loginContainer = document.querySelector('.login-container');
const welcomePage = document.getElementById('welcomePage');
const welcomeUsername = document.getElementById('welcomeUsername');
// 模拟的用户数据库 (在实际项目中,这是从服务器获取的)
const users = {
    'admin': 'password123',
    'user1': '123456'
};
// 模拟的API请求延迟 (网络请求需要时间)
const API_DELAY = 1500; // 1.5秒
// 监听表单提交事件
loginForm.addEventListener('submit', function(event) {
    // 阻止表单默认的提交行为 (页面刷新)
    event.preventDefault();
    // 1. 获取输入值
    const username = usernameInput.value.trim();
    const password = passwordInput.value;
    // 2. 前端验证
    if (!username || !password) {
        showError('用户名和密码不能为空!');
        return;
    }
    // 3. 显示加载状态
    setLoadingState(true);
    // 4. 模拟异步登录请求
    setTimeout(() => {
        // 5. 验证用户名和密码
        if (users[username] && users[username] === password) {
            // 登录成功
            loginSuccess(username);
        } else {
            // 登录失败
            loginFailed();
        }
        // 无论成功失败,都要恢复按钮状态
        setLoadingState(false);
    }, API_DELAY);
});
// 显示错误信息
function showError(message) {
    errorMessage.textContent = message;
    errorMessage.style.display = 'block';
}
// 隐藏错误信息
function hideError() {
    errorMessage.style.display = 'none';
}
// 设置按钮为加载状态
function setLoadingState(isLoading) {
    if (isLoading) {
        loginButton.disabled = true; // 禁用按钮,防止重复点击
        buttonText.textContent = '登录中...';
        loadingSpinner.style.display = 'inline-block';
        hideError(); // 在新请求开始时隐藏旧错误
    } else {
        loginButton.disabled = false; // 重新启用按钮
        buttonText.textContent = '登录';
        loadingSpinner.style.display = 'none';
    }
}
// 登录成功处理
function loginSuccess(username) {
    hideError();
    // 在实际应用中,这里通常会保存一个 token (localStorage)
    localStorage.setItem('isLoggedIn', 'true');
    localStorage.setItem('currentUser', username);
    // 显示欢迎页面,隐藏登录表单
    welcomeUsername.textContent = username;
    loginContainer.style.display = 'none';
    welcomePage.style.display = 'block';
}
// 登录失败处理
function loginFailed() {
    showError('用户名或密码错误!');
    // (可选) 清空密码框
    passwordInput.value = '';
    // (可选) 聚焦到密码框
    passwordInput.focus();
}
// 退出登录函数
function logout() {
    // 清除登录状态
    localStorage.removeItem('isLoggedIn');
    localStorage.removeItem('currentUser');
    // 显示登录表单,隐藏欢迎页面
    welcomePage.style.display = 'none';
    loginContainer.style.display = 'block';
    // 清空输入框
    usernameInput.value = '';
    passwordInput.value = '';
    usernameInput.focus();
}
// 页面加载时检查是否已经登录 (可选,但推荐)
window.addEventListener('DOMContentLoaded', () => {
    const isLoggedIn = localStorage.getItem('isLoggedIn');
    const currentUser = localStorage.getItem('currentUser');
    if (isLoggedIn === 'true' && currentUser) {
        // 如果已经登录,直接显示欢迎页面
        welcomeUsername.textContent = currentUser;
        loginContainer.style.display = 'none';
        welcomePage.style.display = 'block';
    } else {
        // 否则,聚焦到用户名输入框
        usernameInput.focus();
    }
});

如何运行

  1. 创建一个项目文件夹,login-page
  2. 在该文件夹中创建三个文件:index.htmlstyle.cssscript.js
  3. 将上面的代码分别复制到对应的文件中。
  4. 用浏览器打开 index.html 文件即可看到效果。

代码解析和关键点

  1. event.preventDefault():这是最关键的一步,它阻止了表单提交时浏览器默认的刷新页面的行为,让我们有机会用 JavaScript 来处理数据。
  2. DOM 操作:通过 document.getElementById 或更现代的 document.querySelector 获取页面上的元素,以便在 JavaScript 中操作它们(如修改文本、样式、显示/隐藏等)。
  3. setTimeout:用于模拟网络请求的延迟,真实的登录请求是异步的,你需要等待服务器返回结果,而不是立即得到。setTimeout 让我们可以在不真正联网的情况下体验这个过程。
  4. 状态管理
    • 加载状态:通过修改按钮的文本、显示加载动画和禁用按钮,给用户一个“正在处理”的反馈,防止用户重复点击。
    • 错误/成功状态:通过修改 errorMessage 的内容和 loginContainer / welcomePagedisplay 样式,来向用户展示不同的结果。
  5. localStorage:这是一个浏览器提供的简单本地存储,我们用它来模拟“登录状态”的持久化,当你关闭浏览器再打开时,window.addEventListener('DOMContentLoaded', ...) 会检查 localStorage,如果发现你已登录,就会直接让你进入欢迎页面,这是实现“记住我”功能最基础的方式。
  6. 用户体验
    • 表单验证在提交前进行,可以快速给用户反馈。
    • 登录失败后清空密码框并聚焦,提升了用户再次输入的便利性。
    • 加载动画提供了重要的视觉反馈。

进一步的改进方向

  • 真正的后端 API:将 users 对象和验证逻辑替换为 fetchaxios 发送 HTTP 请求到真实的服务器(如 Node.js, Python, PHP 等)。
  • 密码加密:在前端发送密码前,应该使用哈希算法(如 SHA-256)进行一次加密,避免明文传输密码,但更安全的做法是让后端处理所有加密和验证。
  • 更复杂的验证:如邮箱格式验证、密码强度要求等。
  • “记住我”功能:可以通过设置 localStorage 的过期时间或使用 Cookie 来实现。
  • 路由:如果这是一个单页应用,可以使用 react-routervue-router 这样的库来管理页面跳转,而不是直接操作 display 样式。
javascript做网页登录页面
(图片来源网络,侵删)