
构建银行应用第 3 部分用 Fetch API 获取并动态渲染账户数据的完整实战指南【免费下载链接】Web-Dev-For-Beginners24 Lessons, 12 Weeks, Get Started as a Web Developer项目地址: https://gitcode.com/GitHub_Trending/we/Web-Dev-For-Beginners本指南是 Web-Dev-For-Beginners 仓库中7-bank-project系列课程的第三部分主题是把静态银行应用改造成数据驱动的单页应用SPA你将学会用fetch异步请求账户数据、处理跨域CORS、通过安全的 DOM 操作把数据渲染到仪表盘并用templateDocumentFragment高效生成交易列表。读完本文你将掌握一套可复用到任意前后端分离项目的数据获取 → 状态保存 → 动态渲染 → 错误反馈完整链路。⚡ 5 分钟快速开始为繁忙开发者准备的快速通道先跑通链路再深入原理第 1-2 分钟启动 API 服务器cd api npm start并测试连接第 3 分钟用fetch创建基础的getAccount()函数第 4 分钟用actionjavascript:login()接通登录表单第 5 分钟测试登录在控制台看到账户数据# 确认 API 正在运行 curl http://localhost:5000/api # 期望输出: Bank API v1.0.0 # 测试获取账户数据 curl http://localhost:5000/api/accounts/test短短 5 分钟你就能体会到异步数据获取的魔力——它是让现代 Web 应用感觉快速、鲜活的地基。API 服务器的完整接口清单见 7-bank-project/api/README.md服务端实现在 7-bank-project/api/server.js。前置条件动手前请确保以下组件就绪前一课内容完成登录与注册表单即 7-bank-project/2-forms/README.md本课在其基础上继续构建本地服务器安装 Node.js 并运行 API 服务器 以提供账户数据API 连接用curl http://localhost:5000/api测试连接期望响应Bank API v1.0.0这条快速测试能同时验证三件事Node.js 是否正确运行、API 服务器是否存活并响应、你的应用能否触达服务器。现代 Web 应用中的数据获取演进过去二十年Web 应用处理数据的方式发生了剧变。理解这段演进你才能真正明白 AJAX 与 Fetch API 为何强大、为何成为 Web 开发者的必备工具。传统多页应用MPA早期的 Web 世界里每次点击都像切换老式电视的频道——屏幕先黑掉再慢慢调出新内容。每一次交互都意味着整个页面从零重建。为什么这种体验很笨拙每次点击都要从头重建整个页面恼人的页面闪烁会打断用户的思路网络反复下载相同的 header 和 footer白白浪费流量应用用起来更像翻档案柜而不是用软件现代单页应用SPAAJAXAsynchronous JavaScript and XML彻底改变了这一范式。就像国际空间站的模块化设计——宇航员可以更换单个组件而无需重建整体结构——AJAX 允许我们只更新网页的特定部分而不重新加载整页。尽管名字里带着 XML今天绝大多数场景使用的是 JSON但核心原则不变只更新需要变化的部分。为什么 SPA 体验好得多只有真正变化的区域被更新不再有突兀的中断用户始终沉浸在流程中更少的网络数据传输意味着更快加载一切响应迅速像手机上的原生 App演进到现代 Fetch API现代浏览器提供FetchAPI取代了老旧的XMLHttpRequest。两者的区别就像发电报与发电子邮件Fetch API 用 Promise 写出更干净的异步代码并天然支持 JSON。特性XMLHttpRequestFetch API语法复杂的回调式简洁的 Promise 式JSON 处理需要手动解析内置.json()方法错误处理错误信息有限详尽的错误描述现代支持仅向后兼容ES6 Promise 与 async/await结论Fetch API 在 Chrome、Firefox、Safari、Edge 等所有现代浏览器中都能正常工作只有 Internet Explorer 需要额外兼容处理。它为后续要用的 async/await 模式做好了铺垫。实现用户登录与数据获取现在把银行应用从静态展示变成可用应用验证用户凭据然后向其返回特定数据。我们分步构建先做基础认证再加上数据获取能力。第 1 步搭建登录函数地基在app.js中新增login函数处理用户认证async function login() { const loginForm document.getElementById(loginForm); const user loginForm.user.value; }要点拆解async关键字告诉 JavaScript这个函数可能需要等待某些操作通过 ID 获取表单元素取出用户输入的用户名技巧表单里任意输入控件都可以通过name属性直接访问无需额外的getElementById调用表单访问模式所有表单控件都可以通过其name属性在 HTML 中设置作为表单元素的属性来访问这是获取表单数据的简洁可读方式。第 2 步创建账户数据获取函数创建专门从服务器获取账户数据的函数与注册函数模式一致但专注于数据获取async function getAccount(user) { try { const response await fetch(//localhost:5000/api/accounts/ encodeURIComponent(user)); return await response.json(); } catch (error) { return { error: error.message || Unknown error }; } }这段代码实现了用现代fetchAPI异步请求数据以用户名为参数构造GET 请求 URL用encodeURIComponent()安全处理URL 中的特殊字符将响应转换为 JSON 格式便于数据处理优雅地处理错误——返回错误对象而非崩溃⚠️安全提示encodeURIComponent()负责处理 URL 中的特殊字符。它确保消息原样送达防止#、等字符被误解同时也能防止 URL 操纵攻击保证服务器收到预期数据。理解 HTTP GET 请求一个可能让你意外的点fetch不带任何额外选项时默认就是GET请求——这正好适合请让我看看这个用户的账户数据这种场景。GET 像在图书馆礼貌地借书请求已存在的东西而注册时用到的 POST 更像是向馆藏提交一本新书。GET 请求POST 请求目的获取已有数据向服务器发送新数据参数位置URL 路径/查询字符串请求体缓存浏览器可缓存通常不缓存安全性URL/日志中可见隐藏在请求体中对应的服务端行为可以在 7-bank-project/api/server.js 看到GET /api/accounts/:user从内存数据库取出账户并返回 JSON账户不存在时返回404 错误信息。第 3 步把一切串联起来把账户获取函数接入登录流程async function login() { const loginForm document.getElementById(loginForm); const user loginForm.user.value; const data await getAccount(user); if (data.error) { return console.log(loginError, data.error); } account data; navigate(/dashboard); }执行顺序清晰从表单提取用户名 → 向服务器请求账户数据 → 处理过程中的任何错误 → 成功后保存账户数据并导航到仪表盘。Async/Await 模式getAccount是异步函数因此用await暂停执行直到服务器响应避免代码在拿到undefined数据时就继续往下走。第 4 步为数据准备家应用需要一个地方记住加载后的账户信息——类似应用的短期记忆。在app.js顶部添加// 保存当前用户的账户数据 let account null;为什么需要它让账户数据在应用任何位置都能访问初始null表示还没有人登录用户登录或注册成功后更新充当单一数据源single source of truth不会混淆当前登录者是谁第 5 步接通表单把登录函数连接到 HTML 表单更新 form 标签form idloginForm actionjavascript:login() !-- 表单原有输入控件 -- /form这一小改动的作用阻止表单默认的整页重载行为 → 改为调用自定义 JavaScript 函数 → 保持 SPA 式流畅体验 → 让你完全掌控用户点击 Login 后发生的一切。第 6 步增强注册函数为保持一致register函数末尾同样保存账户数据并导航到仪表盘// 在注册函数末尾添加 account result; navigate(/dashboard);带来的收益注册到仪表盘无缝过渡、登录/注册两个流程体验一致、注册成功后立即可用账户数据。测试你的实现创建一个新账户确认一切正常用相同凭据登录出问题时按 F12 查看浏览器控制台确认登录成功后进入仪表盘如果某处不工作别慌——大多数问题只是拼写错误或忘了启动 API 服务器。关于跨域的简短说明你可能会问Web 应用和 API 服务器运行在不同端口它们怎么能通信 这涉及每个 Web 开发者迟早都会碰到的知识点。跨域安全浏览器强制执行同源策略防止不同域之间的未授权通信。它会先验证通信是否被授权才允许数据传输。在本项目的配置中Web 应用运行在localhost:3000开发服务器API 服务器运行在localhost:5000后端服务器API 服务器包含 CORS 头显式授权来自 Web 应用的通信这一配置真实反映了现实开发环境——前端与后端通常运行在各自独立的服务器上。对应源码见 7-bank-project/api/server.jsapp.use(cors({ origin: /http:\/\/(127(\.\d){3}|localhost)/})); app.options(*, cors());注意这里 CORS 白名单用正则只放行了localhost与127.x.x.x来源既允许本地开发又比直接放开*更收敛。让数据在 HTML 中活起来DOM 操作把静态网页变成动态应用——根据用户交互和服务器响应更新内容。就像在暗房里冲洗照片我们把不可见的数据渲染成用户看得见、可交互的内容。为任务选择正确的工具方法擅长场景使用时机安全级别textContent安全显示用户数据任何时候展示文本✅ 坚如磐石createElement()append()构建复杂布局创建新区块/列表✅ 万无一失innerHTML设置 HTML 内容⚠️ 尽量避免❌ 有风险安全显示文本textContenttextContent是展示用户数据时的最佳搭档如同网页的门卫——有害内容一律拦截// 安全可靠的文本更新方式 const balanceElement document.getElementById(balance); balanceElement.textContent account.balance;优点把一切视为纯文本阻止脚本执行、自动清除已有内容、适合简单文本更新、内置防恶意内容保护。动态创建 HTML 元素复杂内容用document.createElement()配合append()// 安全创建新元素的方式 const transactionItem document.createElement(div); transactionItem.className transaction-item; transactionItem.textContent ${transaction.date}: ${transaction.description}; container.append(transactionItem);这种方式的优势程序化创建 DOM 元素、对元素属性与内容保持完全控制、支持复杂嵌套结构、通过结构与内容分离保持安全。⚠️安全考量虽然innerHTML出现在大量教程中但它会执行用户数据里嵌入的script标签易受代码注入攻击。我们使用的textContent与createElement是更安全的替代方案且功能等价。让错误对用户友好目前登录错误只出现在浏览器控制台用户根本看不见。就像飞行员内部诊断与乘客信息系统的区别重要信息要通过正确的渠道传达。实现可见的错误消息能给用户即时的哪里出错了、该怎么继续反馈。第 1 步为错误消息腾出位置在登录按钮之前添加错误消息容器用户会自然看到它!-- 错误消息将显示在这里 -- div idloginError rolealert/div buttonLogin/button这里发生了什么创建一个空的容器平时保持不可见位置靠近用户点击 Login 后自然查看的区域rolealert对屏幕阅读器很有意义——告诉辅助技术这是重要信息唯一的id给 JavaScript 一个明确的定位目标。第 2 步创建实用的辅助函数function updateElement(id, text) { const element document.getElementById(id); element.textContent text; }这个写一次处处用的函数接口简单只需元素 ID 和文本、安全定位并更新 DOM 元素、可复用模式减少代码重复、保证应用内更新行为一致。第 3 步把错误显示在用户看得见的地方把隐藏的控制台消息替换成用户真正看得见的提示更新登录函数// 不再只是写入控制台而是把问题展示给用户 if (data.error) { return updateElement(loginError, data.error); }小小的改动带来巨大差别错误消息正好出现在用户视线所及之处、不再有神秘的静默失败、用户获得即时可操作的反馈、应用显得专业而用心。第 4 步用无障碍设计保持包容前面添加的rolealert可不是装饰品这个属性创建了所谓的 Live Region会立即向屏幕阅读器播报内容变化div idloginError rolealert/div为什么重要屏幕阅读器用户一看到错误消息就能听到无论用户以何种方式导航都能获得同样的关键信息这是让应用服务更多人的简单途径体现你追求包容性体验的专业态度。第 5 步把相同模式应用到注册为保持一致在注册表单实现相同的错误处理添加错误显示元素div idregisterError rolealert/div更新注册函数使用相同的错误展示模式if (data.error) { return updateElement(registerError, data.error); }一致错误处理的好处所有表单提供统一的用户体验、用熟悉模式降低认知负担、可复用代码简化维护、全应用落实无障碍标准。 教学检查点认证模式反思你刚刚实现了一个完整的认证流程这是 Web 开发的基石模式。快速自评能否解释为什么 API 调用要用 async/await如果忘记encodeURIComponent()会怎样错误处理如何改善用户体验现实关联这里学到的异步数据获取、错误处理、用户反馈模式被社交平台到电商网站的每个大型 Web 应用使用你正在构建生产级技能。挑战题如何改造这个认证系统以支持多用户角色客户、管理员、柜员思考所需的数据结构与 UI 改动。创建你的动态仪表盘现在把静态仪表盘改造成显示真实账户数据的动态界面——从印刷版航班时刻表升级为机场实时出发大屏。认识你的数据先看看服务器会返回什么。登录成功时你将获得一整套可用于工作的信息{ user: test, currency: $, description: Test account, balance: 75, transactions: [ { id: 1, date: 2020-10-01, object: Pocket money, amount: 50 }, { id: 2, date: 2020-10-03, object: Book, amount: -10 }, { id: 3, date: 2020-10-04, object: Sandwich, amount: -5 } ] }数据结构说明user用于个性化体验欢迎回来Sarahcurrency确保金额显示正确description账户的友好名称balance至关重要的当前余额transactions包含全部细节的完整交易历史构建一个专业银行仪表盘所需的全部信息都在这里了这段示例数据正是 7-bank-project/api/server.js 中内存数据库预置的test账户。专业提示想立即看到仪表盘效果登录时使用用户名test——它预置了示例数据无需先创建交易就能看到一切正常工作。创建仪表盘显示元素第 1 步更新 HTML 结构把静态的 Balance 部分替换为 JavaScript 可填充的动态占位元素section Balance: span idbalance/spanspan idcurrency/span /section再添加账户描述部分。由于它充当仪表盘内容的标题使用语义化 HTMLh2 iddescription/h2理解这套 HTML 结构余额与币种使用独立span以便单独控制、每个元素用唯一 ID 供 JavaScript 精确定位、用h2表示账户描述遵循语义化 HTML、为屏幕阅读器和 SEO 构建逻辑层级。✅无障碍洞察账户描述充当仪表盘内容标题因此用标题标签语义化标记。可以思考页面上还有哪些元素适合使用标题标签。第 2 步创建仪表盘更新函数function updateDashboard() { if (!account) { return navigate(/login); } updateElement(description, account.description); updateElement(balance, account.balance.toFixed(2)); updateElement(currency, account.currency); }逐步解读校验账户数据存在后再继续 → 未认证用户重定向回登录页 → 用可复用的updateElement更新账户描述 →格式化余额为两位小数 →显示正确的币种符号。金额格式化toFixed(2)确保余额始终像真正的钱——显示75.00而非75。用户会感激熟悉的货币格式。第 3 步确保仪表盘每次访问都刷新为让仪表盘在每次访问时都显示最新数据需要挂接导航系统。如果你完成了第 1 课作业这会很熟悉。在updateRoute()函数末尾添加if (typeof route.init function) { route.init(); }然后更新路由配置加入仪表盘初始化const routes { /login: { templateId: login }, /dashboard: { templateId: dashboard, init: updateDashboard } };这套巧妙设计的作用检查路由是否有特殊初始化代码 → 路由加载时自动执行 → 确保仪表盘总是展示新鲜数据 → 保持路由逻辑干净有序。在参考实现 7-bank-project/solution/app.js 中可以看到同样的模式落地/dashboard路由的init: refreshupdateRoute()末尾执行route.init()并支持popstate前进后退。测试你的仪表盘登录测试账户确认重定向到仪表盘检查账户描述、余额、币种是否正确显示登出再登录确认数据正确刷新用模板构建智能交易列表与其手动为每条交易创建 HTML不如用模板自动生成一致的格式——就像航天制造中的标准化部件模板保证每行交易遵循相同的结构与外观。这种技术可以从几条交易高效扩展到数千条。第 1 步创建交易模板在 HTMLbody中添加可复用的交易行模板template idtransaction tr td/td td/td td/td /tr /template理解 HTML 模板定义单行表格结构、在 JavaScript 克隆填充前保持不可见、包含三个单元格日期、描述、金额、提供可复用的统一格式模式。第 2 步为表格准备动态内容给表格主体添加id方便 JavaScript 定位tbody idtransactions/tbody作用为插入交易行创建明确目标、把表格结构与动态内容分离、便于清空和重新填充交易数据。第 3 步构建交易行工厂函数function createTransactionRow(transaction) { const template document.getElementById(transaction); const transactionRow template.content.cloneNode(true); const tr transactionRow.querySelector(tr); tr.children[0].textContent transaction.date; tr.children[1].textContent transaction.object; tr.children[2].textContent transaction.amount.toFixed(2); return transactionRow; }拆解这个工厂函数获取模板元素 →克隆模板内容以便安全操作 →选中克隆内容中的表格行 → 用交易数据填充每个单元格 →格式化金额为正确的十进制显示 →返回可插入的成品行。第 4 步高效生成多行交易在updateDashboard()中添加以下代码显示全部交易const transactionsRows document.createDocumentFragment(); for (const transaction of account.transactions) { const transactionRow createTransactionRow(transaction); transactionsRows.appendChild(transactionRow); } updateElement(transactions, transactionsRows);理解这种高效方式创建文档片段来批量收集 DOM 操作 →遍历账户数据中的全部交易 → 用工厂函数为每条交易生成一行 → 在加入 DOM 前把所有行收集进片段 →执行一次DOM 更新而不是多次单独插入。⚡性能优化document.createDocumentFragment()还在此基础上对交易按日期倒序排序并为正负金额行分别添加credit/debit样式类。第 5 步把更新函数升级为混合内容updateElement()目前只处理文本内容升级为同时支持文本与 DOM 节点function updateElement(id, textOrNode) { const element document.getElementById(id); element.textContent ; // 清除所有子节点 element.append(textOrNode); }本次升级的关键改进先清除已有内容再添加新内容、接受文本字符串或 DOM 节点作为参数、用append()方法获得灵活性、保持对既有文本用法的向后兼容。试驾你的仪表盘用test账户登录示例数据已就绪导航到仪表盘检查交易行是否正确格式化显示确认日期、描述、金额都正常如果一切正常你应该看到仪表盘上出现完整可用的交易列表你达成的成就构建了可随数据量扩展的仪表盘用可复用模板实现一致格式化实现高效的 DOM 操作技术开发出堪比生产级银行应用的功能 教学检查点动态内容生成架构理解你实现了一条成熟的数据到 UI 管线与 React、Vue、Angular 等框架的模式一脉相承。已掌握的核心概念模板化渲染创建可复用 UI 组件、文档片段优化 DOM 性能、安全 DOM 操作杜绝安全漏洞、数据转换把服务器数据转化为用户界面。行业关联这些技术是现代前端框架的基础——React 的虚拟 DOM、Vue 的模板系统、Angular 的组件架构都建立在这些核心机制之上。思考题如何扩展这套系统以支持实时更新比如新交易自动出现可以考虑 WebSockets 或 Server-Sent Events。从源码验证整套模式本课的每个技术点都能在仓库的参考实现中找到对应落地建议对照阅读7-bank-project/solution/app.js完整前端实现。getAccount/createAccount封装为 Promise 模拟异步见 L95-L102updateElement同时支持文本与节点见 L200-L205updateDashboard用模板克隆 DocumentFragment 货币/日期国际化格式化渲染交易见 L320-L358路由init钩子与登录表单事件绑定见 L220-L2997-bank-project/api/server.jsExpress 实现的 API 服务端。GET /api/accounts/:user返回账户数据、POST /api/accounts创建账户、POST /api/accounts/:user/transactions用 MD5 生成交易 ID 并自动更新余额CORS 白名单限制本地来源7-bank-project/api/README.md完整的 API 路由与请求示例表一个值得注意的细节本课文档描述的应用把数据保存在全局let account中而参考实现升级为冻结的state对象 localStorage持久化 跨标签页同步见 7-bank-project/solution/app.js——这正是下一课状态管理要深入的内容可以先行观察。作业重构并注释你的代码配套作业见 7-bank-project/3-data/assignment.md核心是三项专业重构1. 提取配置常量——把散落各处的服务器 API 地址、错误消息、路由路径与元素 ID 提取为常量// 配置常量 const API_BASE_URL http://localhost:5000/api; const ROUTES { LOGIN: /login, DASHBOARD: /dashboard };2. 创建统一请求函数——用sendRequest()消除createAccount()与getAccount()之间的重复代码同时支持 GET/POST、不同端点、可选请求体与完善的错误处理async function sendRequest(endpoint, method GET, data null) { // 你的实现 }3. 添加专业代码文档——用 JSDoc 说明函数的目的、参数与返回值为复杂逻辑加行内注释用区块标题分组相关函数/** * 认证用户并重定向到仪表盘 * param {Event} event - 表单提交事件 * returns {Promisevoid} - 登录流程完成时解析 */ async function login(event) { // 阻止默认表单提交改用 JavaScript 处理 event.preventDefault(); // 你的实现... }成功标准对照常量完备无魔法字符串、遵循 DRY 原则请求逻辑收敛进sendRequest()、函数均有 JSDoc、代码按区块组织、错误处理因新请求函数而改善。作业中还提供了评价等级优秀/合格/待改进供自测以及提交后完整回归测试用户流、API 调用、错误场景的建议清单。 挑战把应用推向生产级外观让银行应用看起来、用起来都像你真正想用的产品美化用 CSS 把功能性仪表盘变成视觉上吸引人的界面——干净的线条、良好的间距、克制的动画响应式用 media queries 构建适配手机、平板、桌面的响应式设计加点个性交易按颜色编码收入绿色、支出红色、添加图标、hover 效果让界面更富交互性无需精确复刻示例把它当作灵感来源做出你自己的风格。数据管理能力成长时间线回顾整条学习路径基础构建理解客户端-服务器通信、掌握 HTTP 请求/响应周期、学会调试方法→认证精通编写干净的 async/await 代码、高效处理 Promise、实现错误边界创建全局状态模式、构建导航守卫、设计用户反馈系统→动态 UI 开发防止 XSS 漏洞、用 textContent 取代 innerHTML、打造无障碍界面构建可复用 UI 组件、用片段优化性能、扩展以处理大数据集→专业模式实现全面的错误处理、遵循安全最佳实践、创建可维护架构掌握 Fetch API 模式、理解 CORS 配置、构建响应式无障碍 UI。至此你已经用现代 JavaScript 模式构建了一个完整的数据驱动 Web 应用。这些技能可以无缝迁移到 React、Vue、Angular 等框架——无论是探索前端框架、用 WebSockets 实现实时功能、构建支持离线能力的 PWA还是学习进阶的状态管理模式地基都已打好。【免费下载链接】Web-Dev-For-Beginners24 Lessons, 12 Weeks, Get Started as a Web Developer项目地址: https://gitcode.com/GitHub_Trending/we/Web-Dev-For-Beginners创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考