找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

5406

积分

1

好友

738

主题
发表于 3 小时前 | 查看: 5| 回复: 0

本文将继续构建一个功能更完善的用户管理界面。我们来逐步添加真实 Web 应用常见的交互功能:刷新按钮、表单提交添加用户、加载状态管理。

一、更新 index.html —— 添加按钮和表单

将原来的 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>TS + Vite 示例 - 增强版</title>
  <style>
    /* 简单样式,让界面更清晰 */
    body {
      font-family: sans-serif;
      max-width: 600px;
      margin: 2rem auto;
      padding: 0 1rem;
    }
    button, input {
      margin: 0.5rem 0;
      padding: 0.5rem;
    }
    .error {
      color: red;
    }
    .loading {
      color: gray;
      font-style: italic;
    }
  </style>
</head>
<body>
  <div id="app">
    <h1>用户管理</h1>

    <!-- 刷新按钮 -->
    <button id="refresh-btn" type="button">刷新列表</button>

    <!-- 添加用户表单 -->
    <h2>添加新用户</h2>
    <form id="add-user-form">
      <div>
        <label for="name">姓名:</label>
        <input type="text" id="name" name="name" required />
      </div>
      <div>
        <label for="email">邮箱:</label>
        <input type="email" id="email" name="email" required />
      </div>
      <button type="submit">提交</button>
    </form>

    <!-- 用户列表容器 -->
    <h2>用户列表</h2>
    <ul id="user-list">
      <li>加载中...</li>
    </ul>
  </div>
  <script type="module" src="/src/main.ts"></script>
</body>
</html>

变化说明

  • 新增了“刷新列表”按钮(#refresh-btn
  • 新增了表单,包含姓名和邮箱输入框,用于添加用户
  • 添加了简单的 CSS 样式,提升视觉效果
  • 保留原有的用户列表容器 #user-list

二、扩展 src/main.ts —— 增加交互逻辑

将原来的 main.ts 替换为以下代码(在原有基础上扩展,保留原有功能并新增):

/**
 * TypeScript 增强版示例:
 * 1. 获取并展示用户列表(原有)
 * 2. 刷新按钮重新加载列表
 * 3. 表单提交添加新用户(模拟 POST 请求)
 * 4. 加载状态与错误处理
 */

// ---------- 类型定义 ----------
interface User {
  id: number;
  name: string;
  email: string;
  // 实际 API 还有其他字段,我们只关注这三个
}

// 用于创建新用户的类型(id 由后端生成)
interface NewUser {
  name: string;
  email: string;
}

// ---------- DOM 元素获取 ----------
const userListElement = document.getElementById('user-list') as HTMLUListElement;
const refreshBtn = document.getElementById('refresh-btn') as HTMLButtonElement;
const addUserForm = document.getElementById('add-user-form') as HTMLFormElement;
const nameInput = document.getElementById('name') as HTMLInputElement;
const emailInput = document.getElementById('email') as HTMLInputElement;

// ---------- 辅助函数:显示加载/错误状态 ----------
function setLoading(loading: boolean): void {
  if (loading) {
    userListElement.innerHTML = '<li class="loading">加载中...</li>';
  }
}

function showError(message: string): void {
  userListElement.innerHTML = `<li class="error">错误:${message}</li>`;
}

// ---------- 获取用户列表(原有,稍作改造以支持加载状态) ----------
async function fetchUsers(): Promise<User[]> {
  const response = await fetch('https://jsonplaceholder.typicode.com/users');
  if (!response.ok) {
    throw new Error(`HTTP error! status: ${response.status}`);
  }
  const users = await response.json() as User[];
  return users;
}

// ---------- 渲染用户列表 ----------
function renderUserList(users: User[]): void {
  if (!users.length) {
    userListElement.innerHTML = '<li>暂无用户</li>';
    return;
  }
  userListElement.innerHTML = ''; // 清空
  users.forEach(user => {
    const li = document.createElement('li');
    li.textContent = `${user.name} (${user.email})`;
    userListElement.appendChild(li);
  });
}

// ---------- 核心:加载用户并渲染 ----------
async function loadUsers(): Promise<void> {
  setLoading(true);
  try {
    const users = await fetchUsers();
    renderUserList(users);
  } catch (error) {
    showError(error instanceof Error ? error.message : '未知错误');
    console.error(error);
  } finally {
    // 可以不用清除加载状态,因为渲染函数已经替换了内容
  }
}

// ---------- 添加新用户 ----------
async function addUser(newUser: NewUser): Promise<User> {
  // 注意:jsonplaceholder 的 POST 请求不会真的存储,但会返回一个模拟的创建结果
  const response = await fetch('https://jsonplaceholder.typicode.com/users', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(newUser),
  });
  if (!response.ok) {
    throw new Error(`添加失败:${response.status}`);
  }
  const createdUser = await response.json() as User;
  return createdUser;
}

// ---------- 处理表单提交 ----------
async function handleAddUser(event: Event): Promise<void> {
  event.preventDefault(); // 阻止默认提交行为

  // 获取表单数据并校验
  const name = nameInput.value.trim();
  const email = emailInput.value.trim();
  if (!name || !email) {
    alert('请填写姓名和邮箱');
    return;
  }

  // 临时禁用提交按钮,防止重复提交
  const submitBtn = addUserForm.querySelector('button[type="submit"]') as HTMLButtonElement;
  const originalText = submitBtn.textContent;
  submitBtn.disabled = true;
  submitBtn.textContent = '提交中...';

  try {
    // 调用添加 API
    const newUser = await addUser({ name, email });
    // 添加成功后,清空表单
    nameInput.value = '';
    emailInput.value = '';
    // 重新加载用户列表(显示最新数据)
    await loadUsers();
    // 可选:显示成功提示
    console.log('添加成功:', newUser);
  } catch (error) {
    alert(error instanceof Error ? error.message : '添加失败');
    console.error(error);
  } finally {
    // 恢复按钮状态
    submitBtn.disabled = false;
    submitBtn.textContent = originalText || '提交';
  }
}

// ---------- 绑定事件 ----------
refreshBtn.addEventListener('click', loadUsers);
addUserForm.addEventListener('submit', handleAddUser);

// ---------- 初始化:加载用户 ----------
loadUsers();

三、代码详解(新增部分)

1. DOM 元素获取与类型断言

const refreshBtn = document.getElementById('refresh-btn') as HTMLButtonElement;
const addUserForm = document.getElementById('add-user-form') as HTMLFormElement;
const nameInput = document.getElementById('name') as HTMLInputElement;
const emailInput = document.getElementById('email') as HTMLInputElement;
  • 使用 as 断言告诉 TypeScript 这些元素的具体类型,后续可以安全调用 .value.disabled 等属性。

2. 加载与错误状态辅助函数

  • setLoading()showError() 简化了状态管理。
  • loadUsers 中调用 setLoading(true) 显示“加载中...”,成功或失败后会被替换掉。

3. 添加用户函数

async function addUser(newUser: NewUser): Promise<User>
  • 发送 POST 请求,Content-Type: application/json,body 为 JSON 字符串。
  • 返回类型 Promise<User>,表示后端返回创建后的用户(包含 id)。

4. 表单处理函数

  • event.preventDefault() 防止页面刷新。
  • 获取输入值并简单校验。
  • 禁用提交按钮并显示“提交中...”,防止重复点击。
  • 调用 addUser,成功后清空表单、重新加载列表。
  • 使用 try...catch 捕获错误,弹出提示。
  • finally 中恢复按钮状态。

5. 事件绑定与初始化

  • 刷新按钮绑定 loadUsers
  • 表单绑定 handleAddUser
  • 最后调用 loadUsers() 显示初始数据。

四、运行与测试

  1. 启动开发服务器(如果未启动):
    npm run dev
  2. 打开浏览器,你会看到:
    • 初始加载用户列表
    • 点击“刷新列表”按钮,重新加载
    • 填写表单,点击“提交”,会向 JSONPlaceholder 发送 POST 请求(虽然数据不会持久保存,但会返回模拟的新用户),然后列表会刷新并显示新添加的用户(注意 JSONPlaceholder 实际返回的 id 是 11,但列表刷新后可能不会包含它,因为后端并没有真实存储,这里仅演示流程。如果要真实持久化,需要配合自己的后端)
  3. 可以尝试提交空数据,会弹出提示;网络错误时也会显示错误。

用户管理界面功能演示


五、TypeScript 类型安全带来的好处

  • 当你编写 addUser 时,参数类型 NewUser 确保只能传入 { name, email } 对象,避免传错字段。
  • handleAddUser 中,nameInput.value 被推断为 string,可以安全调用 .trim()
  • 使用 as 断言时,我们清楚知道元素存在且类型正确,减少了运行时错误。这正是现代 HTML/CSS/JS 开发中结合静态类型检查的优势所在。

六、总结

你现在已经拥有了一个 带有完整交互的 TypeScript Web 应用雏形,包含:

  • 数据获取(GET)
  • 数据创建(POST)
  • 用户界面更新
  • 加载状态和错误处理
  • 表单验证

所有代码都有清晰的类型注释,并且完全可以在 Vite 开发服务器上运行。继续基于这个模板,你可以根据自己的需求添加更多功能,比如编辑、删除用户,或者使用状态管理库。在 云栈社区 你还可以找到更多关于前端工程化和实战项目的讨论与资源。




上一篇:TypeScript 实战:基于 localStorage 实现完整的用户管理系统(含增删改查)
下一篇:Python 35个内置函数用法详解:从入门到日常开发高频场景
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-4-18 23:58 , Processed in 0.798594 second(s), 41 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表