TodoMVC Angular 示例深入解析:基于 Angular CLI 的组件化 MVC 架构与完整实践指南
TodoMVC Angular 示例深入解析基于 Angular CLI 的组件化 MVC 架构与完整实践指南【免费下载链接】todomvcHelping you select a JavaScript framework - Todo apps for React.js, Angular, Vue and many more项目地址: https://gitcode.com/gh_mirrors/to/todomvc本篇文章以 TodoMVC 仓库中的 Angular 实现examples/angular为核心系统讲解该示例如何用 Angular 的 Service、Component 与 Router 完成一个经典的 TodoMVC 应用涵盖 MVC 职责划分、CRUD 数据服务实现、Hash 路由与本地样式依赖等关键设计并给出开发、构建、测试的完整命令手册。读完本文你将能够独立读懂并复现这个 Angular 示例掌握将 Service 作为 Model、以组件分层组织 View/ViewModel 的工程化套路。一、示例概览一个由 Angular CLI 生成的 TodoMVC 应用本示例是 TodoMVC 官方生态中基于 Angular明确指出该应用由 Angular CLI 版本 17.0.5 生成是一个典型的独立组件standalone component架构应用。Angular 是一个构建在 TypeScript 之上的开发平台作为平台它包含三大支柱组件化框架用于构建可扩展的 Web 应用本示例中头部header、待办列表todo-list、待办项todo-item、页脚footer均被拆分为独立组件集成良好的库集合覆盖路由angular/router、表单管理angular/forms、客户端-服务端通信等广泛特性本示例中用到了 Router 与 Forms 两条关键链路一套开发者工具帮助开发、构建、测试和更新代码即 Angular CLI 提供的ng serve、ng build、ng test等命令。需要特别说明的是虽然 readme 记录其由 CLI 17.0.5 生成但从当前仓库的 examples/angular/package.json 看运行时依赖已升级到angular/core、angular/common、angular/router等均为^21.2.11配套typescript ~5.9.3、zone.js ~0.16.1、rxjs ^7.8.2编译工具链为angular/build与angular/cli的^21.2.9。因此实际运行环境以 package.json 中锁定的版本为准readme 中的 CLI 版本属于生成时的初始信息。二、MVC 架构Service 即 Model组件即 View/ViewModelreadme 的 Implementation details 一节给出了本示例最核心的架构思想在 Angular 中Service 可以把自己的数据与逻辑暴露给其他组件天然适合承担 Model 的职责。因此本示例的 MVC 映射关系为角色Angular 中的落地ModelTodosServicesrc/app/todos.service.tsView各组件的 html 模板*.component.htmlViewModel各组件的 TypeScript 控制器*.component.ts对照经典 MVC 定义Model 维护应用的数据与行为View 将 Model 渲染到 UIController 作为 View 与 Model 之间的接口。在本示例中组件 TS 文件扮演了接口角色——它注入TodosService把用户操作翻译成对 Service 方法的调用再把数据通过 getter 暴露给模板。组件化组织方面readme 说明每个组件文件夹内包含一个用于视图的 html 文件和一个充当控制器的 ts 文件。仓库源码完全印证了这一约定src/app下按功能拆分为四个模块化目录header、todo-list、todo-item、footer外加根组件 app.component.ts、路由配置与数据服务。三、数据层源码解析TodosService 的完整 CRUD 实现Model 层由 src/app/todos.service.ts 承担它是理解整个应用数据流的关键。服务类标注了Injectable({ providedIn: root })意味着它是根级单例整个应用共享同一份待办数据。首先是数据结构定义export interface Todo { title: string; completed: boolean; }每个待办项仅有两个字段标题title与完成状态completed。Service 内部维护todos: Todo[]数组并暴露以下方法构成完整的 CRUD 能力方法职责对应 CRUDaddItem(title)以未完成状态追加新待办CreateremoveItem(todo)按下标定位并splice删除DeleteclearCompleted()用filter过滤掉已完成项Delete批量toggleAll(completed)将所有待办的完成状态统一置位Update批量getItems(type)按all/active/completed返回过滤视图Read其中值得深读的是getItems的分支逻辑todos.service.ts#L39-L48getItems(type all): Todo[] { switch (type) { case active: return this.todos.filter((todo) !todo.completed); case completed: return this.todos.filter((todo) todo.completed); } return this.todos; }它默认返回全部传入active时只保留未完成项传入completed时只保留已完成项。这个方法被列表组件与页脚组件共同调用是筛选视图的数据来源。另一个值得注意的实现细节是toggleAlltodos.service.ts#L29-L37刻意选择了原地修改对象属性而非替换数组源码注释解释了原因如果重建数组并生成新的 todo 对象会强制 Angular 重建每一个app-todo-item从而 detach 掉测试代码或外部观察者可能持有引用的 DOM 节点。这是一个以代码注释形式记录的工程决策理解它有助于避免在类似场景中踩坑。四、组件层解析Header / TodoList / TodoItem / Footer 的分工协作1. 根组件组合而非实现app.component.ts 本身不含业务逻辑仅以standalone: true方式声明并导入三个子组件模板中按 header、todo-list、footer 的顺序渲染。这体现了根组件只做装配的组件化设计思路。2. Header输入与新增header/header.component.ts 通过inject(TodosService)获得服务实例Angular 14 的函数式注入写法维护一个title字段并与模板输入框双向绑定。模板header.component.html使用[(ngModel)]title双向绑定、(keyup.enter)addTodo()响应回车键。addTodo中先trim()去除首尾空格空字符串直接返回非空才调用addItem随后重置title清空输入框——这是 TodoMVC 规范中空白输入不产生待办的经典处理。3. TodoList过滤视图与全选切换todo-list/todo-list.component.ts 是本例中路由驱动数据的中枢。它注入了Location来自angular/common与TodosService通过 getter 动态计算列表数据get todos(): Todo[] { const filter this.location.path().split(/)[1] || all; return this.todosService.getItems(filter); }即从当前浏览器路径中解析出第二段作为筛选类型路径#/active得到active#/completed得到completed默认回退为all。这比在路由守卫中同步状态更轻量是URL 即状态的极简实践。模板todo-list.component.html中还展示了 Angular 17 的控制流语法forfor (todo of todos; track todo) { app-todo-item [todo]todo (remove)removeTodo($event) / }同时通过[hidden]todos.length 0控制主区域显隐toggle-all复选框的(change)事件调用toggleAll其选中态由todos.length 0 !activeTodos.length推导。4. TodoItem单条待办的编辑、完成与删除todo-item/todo-item.component.ts 是交互最密集的组件演示了 Angular 组件间通信的两大基础机制Input({ required: true }) todo!: Todo父组件传入待办数据Output() remove new EventEmitterTodo()把删除请求抛给父组件由父组件调用 Service 完成真正的删除保持子组件不直接触碰全局数据。它的编辑流程值得学习双击进入编辑态startEdit置isEditing true输入框获得焦点时handleFocus把当前标题拷入本地titlecommitEdit提交时若内容为空则触发删除符合 TodoMVC清空即删除规范否则写回todo.titlecancelEdit则恢复原标题。ngAfterViewChecked中通过focusedFor字段记录已聚焦过的编辑会话避免每次变更检测都重复抢焦点——这是处理 Angular 生命周期钩子的一个实用模式。5. Footer统计与筛选链接footer/footer.component.ts 提供剩余项计数activeTodos、已完成计数completedTodos、clearCompleted清理动作并同样从Location解析当前filter以高亮对应链接。模板中使用RouterLink渲染三个筛选入口见 footer.component.html。五、Hash 路由保证跨应用行为一致readme 的 TodoMVC specific details 明确说明示例采用 hash 路由以确保应用与其他框架实现保持一致的 URL 行为Todos 应用部署在静态环境中#/active、#/completed这类 hash 片段不需要服务端重写规则。路由配置位于 src/app/app.routes.tsexport const routes: Routes [ { path: all, component: AppComponent }, { path: active, component: AppComponent }, { path: completed, component: AppComponent }, { path: , redirectTo: /all, pathMatch: full }, ];三个路径复用同一个AppComponent应用形态不变仅列表数据随路径变化空路径重定向到/all。启用 Hash 模式的开关在 src/app/app.config.tsexport const appConfig: ApplicationConfig { providers: [ provideRouter(routes, withHashLocation()) ] };withHashLocation()就是 readme 所说的hash router。应用通过 src/main.ts 中的bootstrapApplication(AppComponent, appConfig)以独立组件方式启动这是 Angular 现代无 NgModule 的引导方式。六、TodoMVC 特定细节样式全部来自本地包readme 指出本示例的所有样式均来自本地 npm 包而非复制样式文件todomvc-app-cssTodoMVC 官方应用样式当前版本^2.4.3todomvc-commonTodoMVC 公共基础样式当前版本^1.0.5。二者都在 examples/angular/package.json 的dependencies中声明全局样式入口在 src/styles.css 中引入。这一做法让示例无需维护整套 CSS聚焦于框架逻辑本身。七、开发、构建与测试命令手册以下是 readme 给出的完整 Angular CLI 命令速查均需在 examples/angular 目录下执行先运行npm install安装依赖1. 开发服务器ng serve启动开发服务器后访问http://localhost:4200/修改任意源文件页面会自动热重载。package.json 中也提供了等价脚本npm start。2. 代码脚手架ng generate component component-name生成一个新组件。ng generate同样支持directive|pipe|service|class|guard|interface|enum|module等各类蓝图可用于快速搭建分层结构。3. 构建ng build构建产物输出到dist/目录。若需监听模式开发构建package.json 提供了npm run watch等价于ng build --watch --configuration development。4. 单元测试ng testreadme 说明单元测试通过 Karma 执行对应的依赖与配置在脚手架生成时引入。需要留意的是本示例的 package.json 中并未显式列出 Karma 与测试相关 devDependencies若要在当前仓库中运行ng test需按 Angular CLI 提示补充测试平台依赖。5. 端到端测试ng e2ereadme 明确指出执行 E2E 测试需要先自行添加一个实现了端到端测试能力的包CLI 本身不内置 E2E 运行器。仓库根目录下另有独立的 Cypress 测试配置cypress.config.js 与 cypress/e2e/spec.cy.js可作为跨示例的 E2E 验证参考。6. 更多帮助ng help查看 Angular CLI 的命令总览与参数说明。八、小结从本示例学到的 Angular 实践以 Service 为 Model把数据与 CRUD 收敛到根级单例服务组件只做视图与交互的翻译层组件即 View/ViewModel*.component.html管渲染、*.component.ts管逻辑目录结构一目了然URL 即筛选状态用Location解析路径段驱动过滤视图配合withHashLocation()让应用可无服务器部署就地变更数组元素toggleAll的原地修改避免了不必要的 DOM 重建注释中说明了权衡理由子组件只发声、不越权Input/Output组合让 todo-item 的删除操作经由父组件转发给 Service保持数据流单向清晰。如果想进一步对照其他框架实现可以在本仓库的 examples 目录下横向比较 React、Vue、Svelte 等版本的架构差异若要动手运行进入 examples/angular 执行npm install后按上文命令即可启动开发服务器。【免费下载链接】todomvcHelping you select a JavaScript framework - Todo apps for React.js, Angular, Vue and many more项目地址: https://gitcode.com/gh_mirrors/to/todomvc创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考