Web-Dev-For-Beginners 银行应用(Bank App)示例解决方案:零框架 SPA 架构拆解与本地运行指南
【免费下载链接】Web-Dev-For-Beginners24 Lessons, 12 Weeks, Get Started as a Web Developer项目地址: https://gitcode.com/GitHub_Trending/we/Web-Dev-For-Beginners
本篇技术指南围绕 7-bank-project 课程项目提供的“银行应用(Squirrel Banking)”完整示例解决方案展开,它使用纯 HTML5、CSS 与原生 JavaScript 构建(不依赖任何框架或库)。通过本文,你将掌握该解决方案的整体架构(模板与路由、登录/注册表单、数据层与状态管理)、本地快速启动方式(API 服务 +
lite-server双端口运行),并从源码级理解每一层实现背后的设计意图,可直接用于把课程四个分节的知识串联成可运行的真实应用。
本仓库(7-bank-project)由微软 Web-Dev-For-Beginners 课程中的第 7 大主题“Build a Bank”构成,配套的英文示例解决方案说明见 7-bank-project/solution/README.md。本文所述的“示例解决方案”即 7-bank-project/solution 目录下的成品,它与课程四节内容一一对应:模板与路由、登录/注册表单、数据获取与使用、状态管理。
解决方案整体概览:你要运行的是什么
示例解决方案的定位一句话概括(引自英文 README 原文):
Example solution for the bank app project, built with vanilla HTML5, CSS and JavaScript (no frameworks or libraries used).
它本质上是一个无构建步骤的前端单页应用(SPA):所有页面结构以 HTML<template>形式静态声明,视图切换由一段极简 hash/History API 路由驱动,数据读写封装在独立的“伪 API”层,最终把账户与交易数据持久化到浏览器localStorage。整个前端由三份静态文件组成:
| 文件 | 职责 |
|---|---|
| 7-bank-project/solution/index.html | 页面挂载点、登录/注册视图模板、仪表盘视图模板、交易弹窗模板与新增交易表单模板 |
| 7-bank-project/solution/styles.css | 设计令牌(design tokens)、明暗主题、布局与组件样式 |
| 7-bank-project/solution/app.js | 常量、格式化工具、数据层、状态管理、路由、认证与仪表盘逻辑、初始化入口 |
| 7-bank-project/solution/logo.svg | 应用品牌 Logo |
最终的界面效果正是你在浏览器打开后会看到的两大页面——登录/注册页与账户仪表盘页:
银行应用登录与注册界面
银行应用账户仪表盘界面
启动前置条件与整体运行架构
在启动前端之前,先理解整个项目采用**双服务(双端口)**结构:
- API 服务:由 7-bank-project/api/server.js 提供的 Express 后端,监听端口
5000,负责账户与交易数据存取。 - 前端静态服务:示例解决方案本身是纯静态文件,任何 Web 服务器均可托管;课程默认使用
npx lite-server在端口3000启动开发服务器。
解决方案 README 的启动要求原文为:“First make sure you have the API server running”(确保 API 服务器已先运行)。API 服务的安装与启动方式详见 7-bank-project/api/README.md:进入api目录后执行npm install安装依赖,再执行npm start,服务器即开始监听5000端口。
需要特别说明的是:API 服务器会与前端服务器同时运行,请勿关闭(英文原文档明确指出 “This server will be running together with the main bank app server terminal (listening on port 3000), do not close it.”)。同时,API 的所有条目存储在内存中、不做持久化——服务一旦停止,全部数据即丢失;而前端当前实现则将账户数据镜像持久化在浏览器
localStorage中,两种数据存储边界需要区分清楚(详见下文“数据层”章节)。
本地启动的完整步骤
结合英文原文档与仓库实际结构,完整的三步启动流程如下:
克隆仓库:将本仓库通过
git clone拉取到本地,进入仓库根目录。先启动 API 服务(终端 A):
cd 7-bank-project/api npm install # 安装依赖,耗时取决于网络状况 npm start # 启动后监听 http://localhost:5000api目录中还提供了一份可交互的 REST 请求样例文件 7-bank-project/api/api.http,安装 VS Code 的 REST Client 扩展后可直接逐个发送请求验证接口。再启动前端静态服务(终端 B):
cd 7-bank-project/solution npx lite-server .该命令会以当前目录为根启动一个开发用 Web 服务器,默认监听端口
3000。此时打开浏览器访问http://localhost:3000即可看到应用。
提示:由于需要运行 API,本地已必然装有 Node.js,因此 README 直接推荐
npx lite-server .而不再额外要求安装任何静态服务器。若端口3000被占用,lite-server会自动尝试寻找下一个可用端口,请注意观察终端输出中的实际地址。
后端 API 一览:前端依赖的接口契约
虽然当前示例前端的最终数据层实现在本地完成(见下一节),但它预留了指向真实 API 的地址常量;API 的完整路由契约(见 7-bank-project/api/README.md 及 server.js 中每个处理器)如下:
| 方法 | 路径 | 说明 |
|---|---|---|
GET | /api/ | 获取服务器信息 |
POST | /api/accounts/ | 创建账户,示例请求体:{ user: 'Yohan', description: 'My budget', currency: 'EUR', balance: 100 } |
GET | /api/accounts/:user | 获取指定账户全部数据 |
DELETE | /api/accounts/:user | 删除指定账户 |
POST | /api/accounts/:user/transactions | 新增交易,示例请求体:{ date: '2020-07-23T18:25:43.511Z', object: 'Bought a book', amount: -20 } |
DELETE | /api/accounts/:user/transactions/:id | 删除指定交易 |
从 server.js 的源码可以印证几个实现细节:
- 服务端口读取环境变量
const port = process.env.PORT || 5000,可用PORT覆盖默认值; - 内存数据库
db预置了一个演示账户test(货币符号$、余额75,含 3 条演示交易),方便 API 链路快速验证; - 账户创建接口对缺失参数返回
400、账户重复返回409; - 交易 ID 并非随机数,而是对
date + object + amount取MD5 哈希生成,同一笔交易重复提交会被409拒绝(去重设计); - CORS 白名单限定了
http://(127.x.x.x|localhost)来源,保证本地双端口联调可用。
在 VS Code 中配合 7-bank-project/api/api.http(内含创建账户、查询、删除账户、添加/删除交易的完整示例)可以快速手工联调这组接口。
架构纵深:纯 JavaScript 如何支撑一个可用的 SPA
从源码结构看,示例解决方案没有使用 Vue/React 等框架,而是用四套自制机制完成了 SPA 的全部能力。这与课程四个分节的训练目标一一对应,是理解整个示例的最佳切入点。
1. 模板与路由(对应 1-template-route 课程)
所有“页面”以 HTML<template>元素静态声明在 index.html 中:
#login模板(index.html 第 25 行起):登录 + 注册双面板;#dashboard模板(第 100 行起):余额摘要、交易表格、新增交易弹窗;#transaction模板(第 211 行起):单行交易记录。
路由层在 app.js 中实现为一张表 +History API:
const routes = { '/dashboard': { title: 'My Account', templateId: 'dashboard', init: refresh }, '/login': { title: 'Login', templateId: 'login', init: attachAuthHandlers } };navigate(path)调用history.pushState写入 URL;updateRoute()根据当前路径取出对应<template>,克隆其内容并渲染进#app挂载点,随后执行该路由的init钩子;popstate监听器负责浏览器前进/后退。路由粒度非常轻——一套{ title, templateId, init }元数据即描述了一个页面。
2. 认证与表单(对应 2-forms 课程)
登录与注册逻辑位于 app.js:提交前先调用form.checkValidity()做浏览器原生校验,不通过则reportValidity();通过后读取表单字段,调用数据层接口,失败时将错误写入带role="alert"的错误容器,成功后updateState保存账户并navigate('/dashboard')跳转。
3. 数据层(对应 3-data 课程)
这是最值得留意的一处实现选择。当前示例的最终代码将数据访问全部封装成“可替换的伪 API”:
- 常量
serverUrl = 'http://localhost:5000/api'(app.js 第 5 行)注释为 “reserved for future server swap”(保留给未来切换真实服务端); - 具体实现
getAccount、createAccount、createTransaction(app.js 第 90–170 行)则基于localStorage存取,并用setTimeout(60–80ms)模拟网络延迟,保持函数签名与将来替换为真实fetch调用一致。
例如createAccount会校验用户名非空、用户不重复,并对currency调用isIsoCurrency规范化;createTransaction生成uuid()作为交易 ID、累加账户余额并追加交易记录。这种“接口先行、实现可换”的结构,正是课程第 3 节“数据获取与使用”所训练的抽象思维落地。
4. 状态管理(对应 4-state-management 课程)
状态集中在 app.js:state对象通过Object.freeze保持不可变,任何更新都必须经updateState(property, newData)——它内部以{ ...state, [property]: newData }生成新对象并重新冻结,同时把活跃账户写入localStorage(key 为savedAccount)。此外还实现了两项进阶能力:
- 跨标签页同步:监听全局
storage事件,当其他标签页改动了账户/交易数据时,自动触发refresh(); - Schema 迁移脚手架:
migrateSchema()读取schemaVersion,为将来数据结构升级预留了迁移入口(app.js 第 80–88 行)。
所有账户则保存在另一把 keyaccounts下,getAccounts/saveAccounts是仅有的两个读写入口,数据读取统一经safeParse兜底,避免脏 JSON 导致崩溃。
5. 仪表盘渲染细节
updateDashboard()(app.js 第 320–358 行)负责把状态渲染成界面:金额通过toCurrency()做本地化货币格式化,交易按日期降序排序后逐行克隆#transaction模板填充,正负金额分别挂上credit/debitCSS 类以便视觉区分。新增交易以无原生<dialog>的方式自行实现模态弹窗(.dialog+.show类),并具备完整的焦点管理:打开即聚焦日期输入框,Escape键关闭并归还焦点到“Add transaction”按钮——这符合 Web 无障碍指南中对话框键盘交互的要求。
无障碍与主题细节(styles.css 中的工程化实践)
7-bank-project/solution/styles.css 并非简单样式表,而是体现了若干值得借鉴的工程实践:
- CSS 设计令牌:
--primary、--surface、--radius、--space-*等自定义属性统一定义品牌色、中性色、圆角与间距(styles.css 第 5–48 行); - 随系统明暗自适应:
@media (prefers-color-scheme: dark)自动切换深色令牌组,<html contenteditable="false">【免费下载链接】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),仅供参考