ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Web-Dev-For-Beginners 银行应用实战(一):用 HTML 模板与客户端路由构建单页应用

Web-Dev-For-Beginners 银行应用实战(一):用 HTML 模板与客户端路由构建单页应用 Web-Dev-For-Beginners 银行应用实战一用 HTML 模板与客户端路由构建单页应用【免费下载链接】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」项目的第 1 课系统讲解如何不依赖任何框架仅用原生 HTML 的template元素、JavaScript 路由表与浏览器 History API从零构建一个具备登录页与仪表盘页的银行单页应用SPA。学完本篇你将掌握模板克隆渲染、URL 与视图的映射、无刷新导航以及浏览器后退/前进按钮的正确接入方法这些正是 React Router、Vue Router 等现代框架路由方案背后的底层原语。为什么需要单页应用从多页应用到 SPA 的演进课程开篇用 1969 年阿波罗 11 号制导计算机「在不重启整个系统的前提下切换不同程序」来类比现代 Web 应用只更新需要变化的部分而不是每次交互都整页重载。传统多页应用MPA与单页应用SPA的差异可以从课程给出的对照表完整看到维度传统多页应用现代单页应用导航每个屏幕都触发整页加载即时切换内容性能每次都要完整下载 HTML较慢局部更新更快用户体验页面闪烁、体验割裂平滑、类 App 的过渡数据共享页面间共享数据困难状态管理容易开发需要维护多个 HTML 文件单个 HTML 动态模板理解这一演进的关键点在于传统应用的每一次导航动作都对应一次服务器请求URL 与服务器上的 HTML 文件一一对应现代 SPA只加载一次页面之后由 JavaScript 动态更新内容用户预期已经转向即时、无缝的交互性能收益包括带宽占用下降与响应速度提升。在本课中我们将构建一个包含登录页与仪表盘两个屏幕的银行应用用到的三个核心技术是HTML 模板可复用的屏幕蓝图、JavaScript 路由切换屏幕的系统与浏览器 History API保证后退按钮按预期工作。这些正是 React、Vue、Angular 等框架底层使用的同一套基础技术。环境准备与项目初始化课程要求本地起一个 Web 服务器来测试应用。最简单的方案是安装 Node.js 后在项目目录下运行npx lite-server这个命令会启动本地服务器并自动在浏览器中打开应用。项目目录结构在本地创建一个名为bank的文件夹内含index.html。本课结束时项目结构如下bank/ ├── index.html !-- 主 HTML包含所有模板 -- ├── app.js !-- 路由与导航逻辑 -- └── style.css !-- 可选供后续课程使用 --文件职责划分index.html包含全部模板并提供应用结构app.js负责路由、导航与模板管理模板定义登录页、仪表盘等各屏幕的 UI。HTML5 起始模板boilerplate课程从以下 HTML5 boilerplate 起步!DOCTYPE html html langen head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 titleBank App/title /head body !-- This is where youll work -- /body /html这份起始模板提供了HTML5 文档结构与正确的 DOCTYPE 声明、支持国际化文本的 UTF-8 字符编码、适配移动端的 viewport meta 标签、显示在浏览器标签页的描述性标题以及一个干净的body区域供后续搭建应用。HTML 模板单文件承载多屏幕课程用古腾堡 15 世纪 40 年代发明活字印刷术做类比与其整页雕刻不如制作可复用的字块按需排版。HTML 模板遵循同样的原则——不为一屏建一个文件而是定义可复用的结构按需实例化。为多屏幕 Web 页面创建独立 HTML 文件的做法有两个明显缺陷切换屏幕时必须重新加载整个 HTML速度慢不同屏幕之间共享数据困难。另一种方案是只保留一个 HTML 文件用template元素定义多个 HTML 模板。模板是不可被浏览器直接显示的 HTML 块必须在运行时由 JavaScript 实例化。搭建登录与仪表盘模板首先在body中加入占位元素——这是所有屏幕的挂载点div idappLoading.../div该占位元素的作用创建 ID 为app的容器用于承载所有屏幕在 JavaScript 初始化第一个屏幕前显示加载提示为动态内容提供唯一挂载点便于 JavaScript 通过document.getElementById()精确定位。专业提示由于该元素的内容会被替换可以放入加载提示或指示器在应用加载期间展示。接着添加登录页模板目前只放标题和一个用于导航的链接template idlogin h1Bank App/h1 section a href/dashboardLogin/a /section /template登录模板要点用唯一 IDlogin供 JavaScript 定位主标题确立应用品牌section语义化地分组相关内容导航链接把用户带到仪表盘。然后添加仪表盘模板包含三个区域带标题与登出链接的页头、当前账户余额、以表格展示的交易列表template iddashboard header h1Bank App/h1 a href/loginLogout/a /header section Balance: 100$ /section section h2Transactions/h2 table thead tr thDate/th thObject/th thAmount/th /tr /thead tbody/tbody /table /section /template仪表盘模板要点用语义化header组织页面与导航跨屏幕一致展示应用名以强化品牌提供回到登录页的登出链接独立section展示账户余额用结构规范的 HTML 表格组织交易数据表头定义 Date、Object、Amount 三列tbody留空供后续动态注入内容。专业提示想预览模板渲染后的效果可以把template与/template标签用!-- --注释掉内容便会立即显示。模板系统的架构收益模板架构带来四方面价值可复用性一次定义、多实例使用、性能无冗余 HTML 解析、可维护性UI 结构集中管理、灵活性内容动态切换。自检问题如果去掉template标签内容会立即显示并失去模板功能模板上的id属性用于唯一标识虽然也可以用 class但id更贴合「每个模板唯一」的定位语义。用 JavaScript 激活模板三步渲染法直接在浏览器中打开当前 HTML页面会停留在Loading...因为还缺少实例化模板的 JavaScript。模板实例化通常分三步在 DOM 中取到模板元素例如用document.getElementById克隆模板元素使用cloneNode挂载到 DOM 中的可见元素之下例如用appendChild。流程可视化第一步在 DOM 结构中找到隐藏模板第二步创建一份可安全修改的工作副本第三步把副本插入页面可见区域最终结果是用户可交互的功能性屏幕。创建 app.js 并编写 updateRoute在项目目录新建app.js并在 HTML 的head中引入script srcapp.js defer/scriptdefer属性确保脚本在 HTML 解析完成后执行从而能访问全部已加载的 DOM 元素这是现代脚本加载与性能的最佳实践仓库中的完整解决方案同样采用script srcapp.js defer/script的写法见 7-bank-project/solution/index.html。在app.js中编写第一个渲染函数function updateRoute(templateId) { const template document.getElementById(templateId); const view template.content.cloneNode(true); const app document.getElementById(app); app.innerHTML ; app.appendChild(view); }逐步拆解按唯一 ID 找到模板元素用cloneNode(true)深拷贝模板内容找到内容将要显示的应用容器清空容器中的既有内容把克隆的模板内容插入可见 DOM。调用一次看看效果updateRoute(login);这一步把登录模板激活演示了如何在应用的不同屏幕间以编程方式切换登录页随即替代了Loading...消息。思考题app.innerHTML ;的作用是什么没有它会发生什么——如果不先清空容器多次渲染会导致内容叠加出现多个屏幕并存。创建路由把 URL 映射到模板路由的本质是把 URL 连接到正确的内容如同早期电话总机接线员接收来电并转接至目标。Web 路由接受 URL 请求并决定显示什么内容。传统做法是服务器为不同 URL 提供不同 HTML 文件而 SPA 需要在 JavaScript 中自行处理路由以获得对用户体验与性能更大的控制权。多文件站点中文件路径会自动反映在 URL 上例如mywebsite/index.html mywebsite/login.html mywebsite/admin/index.html以mywebsite为根目录启动服务器后URL 映射为https://site.com -- mywebsite/index.html https://site.com/login.html -- mywebsite/login.html https://site.com/admin/ -- mywebsite/admin/index.html但我们的应用只有一个 HTML 文件包含所有屏幕默认行为帮不上忙必须手动建立映射并用 JavaScript 更新显示的模板。路由表与基于 pathname 的查询在app.js顶部添加一个简单对象实现 URL 路径到模板的映射const routes { /login: { templateId: login }, /dashboard: { templateId: dashboard }, };这份路由配置在 URL 路径与模板标识符之间建立映射采用对象语法键为 URL 路径值为模板信息可轻松查询任意 URL 该显示哪个模板结构可扩展未来可添加新路由。接下来改造updateRoute不再直接传templateId而是先读取当前 URL再用映射查出对应的模板 ID使用window.location.pathname只取 URL 中的路径部分function updateRoute() { const path window.location.pathname; const route routes[path]; const template document.getElementById(route.templateId); const view template.content.cloneNode(true); const app document.getElementById(app); app.innerHTML ; app.appendChild(view); }这段代码从浏览器 URL 提取当前路径、在 routes 对象中查找对应路由配置、从配置中取出模板 ID、沿用之前的模板渲染流程从而形成随 URL 变化而响应的动态系统。可以手动修改浏览器地址栏中的 URL 来验证效果。思考题如果输入一个未知路径会发生什么——此时routes[path]为undefined访问route.templateId会抛错需要引入回退处理这正是下一节要解决的问题。添加导航无刷新的 URL 与内容同步路由建立后用户需要一种在应用内移动的方式。传统网站点击链接会整页重载而我们希望既更新 URL 也更新内容且不刷新页面。需要协调两件事更新浏览器 URL便于收藏与分享以及显示对应内容。navigate 函数与 History API第二件事已由updateRoute完成现在解决如何更新当前 URL。使用history.pushState它能在不重载 HTML 的情况下更新 URL 并在浏览历史中创建新条目function navigate(path) { window.history.pushState({}, path, path); updateRoute(); }该导航函数用history.pushState把浏览器 URL 更新为新路径在历史栈中新增条目保证后退/前进按钮正常工作触发updateRoute()显示对应模板全程保持单页应用体验、不刷新页面。⚠️重要说明HTML 锚点元素a href单独使用虽然能创建指向不同 URL 的超链接但点击时默认会让浏览器重载 HTML。自定义 JavaScript 处理路由时必须在点击事件上用preventDefault()阻止该默认行为。兜底路由处理未知路径现在可以处理路径不匹配任何路由的问题给updateRoute加上回退逻辑function updateRoute() { const path window.location.pathname; const route routes[path]; if (!route) { return navigate(/login); } const template document.getElementById(route.templateId); const view template.content.cloneNode(true); const app document.getElementById(app); app.innerHTML ; app.appendChild(view); }关键点先检查当前路径是否存在对应路由访问无效路由时重定向到登录页提供防止导航崩溃的兜底机制确保即使 URL 写错用户也始终能看到有效屏幕。拦截链接点击再创建一个函数在链接被点击时取出目标 URL 并阻止浏览器默认行为function onLinkClick(event) { event.preventDefault(); navigate(event.target.href); }该点击处理器用preventDefault()阻止浏览器对链接的默认处理从被点击的链接元素中取出目标 URL改为调用自定义导航函数而非重载页面保持平滑的单页应用体验。然后给两个链接绑定该处理器a href/dashboard onclickonLinkClick(event)Login/a ... a href/login onclickonLinkClick(event)Logout/aonclick属性把 click 事件绑定到 JavaScript 代码此处为调用navigate()让每个链接都接入自定义导航系统同时保持可收藏、可分享的正确 URL 结构。现在点击链接应能在应用的不同屏幕间自由切换。关于旧浏览器兼容的补充history.pushState是 HTML5 标准的一部分被所有现代浏览器实现。如果面向旧浏览器可以采用替代技巧在路径前使用 hash#例如/#/dashboard。hash 最初的设计目的是页面内部锚点跳转利用它做路由可以配合普通锚点导航工作且不会重载页面。让后退/前进按钮工作popstate 事件后退与前进按钮是 Web 浏览的基础功能用户对此有明确预期。浏览器维护着一个历史栈我们一直在用history.pushState向其中追加条目但当用户在这个历史里来回移动时应用必须响应并更新显示的内容。使用history.pushState会不断在浏览器导航历史中创建新条目长按浏览器后退按钮即可看到类似下面的效果如果此时连续点击后退按钮会发现 URL 在变化、历史在更新但显示的模板始终不变。原因在于应用并不知道「每次历史变化都要调用updateRoute()」。查阅history.pushState文档可知当状态改变即移动到不同 URL时会触发popstate事件我们可以用它修复这个问题。接入 popstate 并初始化在app.js末尾添加window.onpopstate () updateRoute(); updateRoute();这段历史集成代码监听用户使用浏览器按钮导航时触发的popstate事件用箭头函数简洁声明事件处理器普通函数效果相同每次历史状态变化时自动调用updateRoute()页面首次加载时也调用updateRoute()完成初始化确保无论用户以何种方式导航正确模板始终显示。之后在浏览器中使用后退/前进按钮就能看到显示的路由被正确更新了。对照仓库源码完整解决方案中的路由实现本课仓库自带一份可运行的完整实现位于 7-bank-project/solution/由 index.html、app.js、styles.css 等组成可作为本课练习的参考与延伸。对照源码可以看到课程中的三个核心概念在工程化场景下的具体形态1. 路由表得到扩展。课程中的 routes 只含templateId而解决方案的路由表7-bank-project/solution/app.js为每条路由增加了title页面标题与init路由初始化回调const routes { /dashboard: { title: My Account, templateId: dashboard, init: refresh }, /login: { title: Login, templateId: login, init: attachAuthHandlers } };这正是课程末尾作业7-bank-project/1-template-route/assignment.md要求实现的两个增强功能——动态页面标题与路由生命周期钩子——的参考答案updateRoute()在渲染完成后执行route.init()并通过document.title route.title同步浏览器标签页标题见 7-bank-project/solution/app.js。2. 导航与回退逻辑一致。解决方案的navigate()7-bank-project/solution/app.js用history.pushState({ path }, , path)把路径同时写入历史状态与 URLupdateRoute()7-bank-project/solution/app.js通过history.state?.path || window.location.pathname解析当前路径并将无法匹配的路由回退到/dashboard。3. popstate 采用 addEventListener。课程用window.onpopstate () updateRoute()赋值解决方案则用更通用的window.addEventListener(popstate, () updateRoute())7-bank-project/solution/app.js两种写法等价。4. 初始化时播种历史状态。解决方案的init()7-bank-project/solution/app.js会用history.replaceState为首次访问设置初始路径已登录进/dashboard否则进/login再调用updateRoute()完成首屏渲染——这与课程中「初始化调用 updateRoute()」的引导一脉相承。5. 模板的三步渲染法贯穿始终。解决方案的updateDashboard()7-bank-project/solution/app.js对每笔交易执行「getElementById(transaction)→template.content.cloneNode(true)→ 填充单元格 →appendChild」的完整流程并借助一个独立的template idtransaction交易行模板见 7-bank-project/solution/index.html批量生成表格行。这说明模板渲染模式在真实应用中会被反复复用甚至模板套模板。实践挑战与课后作业课程提供了两档挑战和一份作业用于把学到的路由知识推向实战GitHub Copilot Agent 挑战404 页面使用 Agent 模式完善银行应用新建一个id为not-found的 HTML 模板展示带样式的友好 404 错误页修改 JavaScript 路由逻辑让用户在访问无效 URL 时显示该模板并添加一个「Go Home」按钮跳回登录页。挑战添加 Credits 页面新增第三个页面展示应用版权信息。目标创建内容结构合理的 HTML 模板在 routes 配置对象中加入新路由包含进出 Credits 页的导航链接验证所有导航在浏览器历史下均正常工作。课后作业增强路由assignment.md作业要求为路由实现增加两个生产级特性特性一动态页面标题。为每个模板配置标题模板切换时同步更新window标题。意义在于改善浏览器标签页的用户体验、增强屏幕阅读器等辅助技术可达性、为收藏与历史提供更好上下文。实现路径扩展 routes 对象加入title字段修改updateRoute()动态更新document.title验证导航时标题正确变化。特性二路由生命周期钩子。增加一个在模板渲染后执行代码的选项例如每次显示仪表盘时在控制台打印Dashboard is shown。意义在于支持特定路由加载时的自定义逻辑分析、日志、初始化、为更复杂的路由行为打基础、演示观察者模式。实现路径在路由配置中增加可选的回调函数属性模板渲染完成后调用该回调如果存在确保任何定义了回调的路由都生效验证访问仪表盘时控制台出现消息。评分标准Rubric强调优秀——两个特性均实现且可用并且新加入的路由也能获得标题与回调支持合格——两个特性可用但行为硬编码、不能通过 routes 声明配置新增第三条路由时部分失效待改进——缺失或未能正常工作。其他建议课程还给出递进式练习清单用浏览器后退/前进按钮测试导航手动输入不同 URL 测试路由打开 DevTools 检查模板如何被克隆进 DOM用console.log跟踪路由流程以及给模板添加 CSS、实现 404 页面、增加加载状态与切换过渡。延伸学习从手写路由到框架路由路由是 Web 开发中出乎意料复杂的部分。课程建议阅读 Azure Static Web App 的路由文档并尝试解释其中某些设计决策为何必要。进一步的学习方向包括探索 React Router、Vue Router 等流行框架如何实现客户端路由研究 hash 路由与 History API 路由的差异与取舍了解服务端渲染SSR对路由策略的影响调查渐进式 Web 应用PWA如何处理路由与导航。总结完成本课后你已掌握模板架构可复用的 HTML 组件与动态内容渲染、客户端路由无需刷新页面的 URL 管理与导航、浏览器集成History API 与后退/前进按钮支持、事件驱动系统导航与用户交互处理、DOM 操作模板克隆、内容切换与元素管理、错误处理无效路由的优雅回退以及性能模式高效的内容加载与渲染策略。这些技能直接适用于现代 Web 应用开发React、Vue、Angular 等框架、渐进式 Web 应用、企业级多视图仪表盘、电商平台商品目录、购物车、结账流程、内容管理与混合移动开发。你现在可以用恰当的关注点分离架构设计单页应用实现随应用复杂度扩展的客户端路由系统借助浏览器开发者工具调试复杂的导航流程通过高效模板管理优化性能设计出原生、响应式的用户体验——并以此为起点进一步探索现代前端框架与高级状态管理。【免费下载链接】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),仅供参考
返回列表