十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

AngularJS + RequireJS TodoMVC 实战:模块化加载、应用引导与单元测试

AngularJS + RequireJS TodoMVC 实战:模块化加载、应用引导与单元测试 AngularJS RequireJS TodoMVC 实战模块化加载、应用引导与单元测试【免费下载链接】todomvcHelping you select a JavaScript framework - Todo apps for React.js, Angular, Vue and many more项目地址: https://gitcode.com/gh_mirrors/to/todomvc本文基于 TodoMVC 仓库中的 AngularJS RequireJS 示例examples/angularjs_require深入剖析如何将 AngularJS 1.x 与 RequireJS 结合使用从require.config的模块路径与 shim 配置、手动angular.bootstrap引导、控制器/指令/服务的 AMD 化拆分到基于 Jasmine 的单元测试闭环。读完本文你将掌握一套完整的AngularJS AMD 模块加载 可测试架构实战方案可直接迁移到自己的项目中。示例概览为什么需要 AngularJS RequireJS 组合AngularJS 的理念是扩展 HTML 的词汇表——用指令、表达式、过滤器让声明式 HTML 承载动态视图逻辑。但对于中大型应用把所有控制器、指令、服务堆在一个文件里显然不可行。TodoMVC 的这个示例给出了一个经典解法用 RequireJS 承担模块加载与依赖管理用 AngularJS 承担视图与业务逻辑。该示例的依赖清单见 package.json非常精简angular^1.3.13MVVM 核心框架requirejs^2.1.15AMD 模块加载器todomvc-app-css、todomvc-commonTodoMVC 通用样式与基础脚本。整个应用的源码结构如下examples/angularjs_require/ ├── index.html # 唯一入口页面data-main 指向 js/main ├── js/ │ ├── main.js # RequireJS 全局配置paths / shim / deps │ ├── app.js # 模块装配与手动 bootstrap │ ├── controllers/todo.js # TodoController 业务逻辑 │ ├── directives/todoEscape.js # Esc 键处理指令 │ ├── directives/todoFocus.js # 编辑态聚焦指令 │ └── services/todoStorage.js # localStorage 持久化服务 └── test/ ├── gruntfile.js # Jasmine 测试任务配置 └── unit/directives/ # 指令级单元测试 ├── todoEscapeSpec.js └── todoFocusSpec.js运行与单元测试readme 给出的两个命令原文档 readme.md 的Unit Tests一节给出了最核心的实操入口npm install npm test执行链路如下npm install安装依赖Angular、RequireJS、TodoMVC 样式、jasmine 相关 Grunt 插件npm test触发 test/gruntfile.js 中注册的jasmine任务Grunt 通过grunt-contrib-jasmine启动无头测试配合grunt-template-jasmine-requirejs模板让测试用例也能以 RequireJS 模块的方式加载。关键在于test/gruntfile.js中的templateOptions它复用了应用自身的 js/main.js 作为requireConfigFile同时设置baseUrl: ../js并把jquery与angular-mocks补充进测试专用的paths。也就是说——测试环境与应用运行环境共享同一套 RequireJS 配置只是额外注入了测试需要的依赖。这是该示例最具复用价值的设计之一。RequireJS 加载策略main.js 的配置拆解入口页面 index.html 末尾只加载了一个脚本script>require.config({ paths: { angular: ../node_modules/angular/angular }, shim: { angular: { exports: angular } }, deps: [app] });三个配置项各司其职paths把模块名angular映射到node_modules中的真实文件路径。由于 AngularJS 1.x 的 UMD 支持有限这里必须显式声明路径而非依赖自动解析shim声明 AngularJS 不是 AMD 模块加载完成后以全局变量angular作为其导出值。exports: angular让后续require([angular])拿到的是全局angular对象deps配置完成后自动加载app模块即 js/app.js正式启动应用装配。应用引导app.js 的嵌套 require 与手动 bootstrapAngularJS 常规用法是在 HTML 中写ng-app指令自动引导。但本示例刻意放弃ng-app改用 js/app.js 手动引导原因在于依赖是异步加载的必须等所有 AMD 模块就绪后再启动 Angular 运行时。require([angular], function (angular) { require([ controllers/todo, directives/todoFocus, directives/todoEscape, services/todoStorage ], function (todoCtrl, todoFocusDir, todoEscapeDir, todoStorageSrv) { angular .module(todomvc, [todoFocusDir, todoEscapeDir, todoStorageSrv]) .controller(TodoController, todoCtrl); angular.bootstrap(document, [todomvc]); }); });这里有两处嵌套require外层先确保angular可用内层再并行加载业务模块。每个模块指令、服务在自身文件中返回一个独立的 Angular 模块名app.js把它们作为依赖数组传入angular.module(todomvc, [...])最后调用angular.bootstrap(document, [todomvc])完成手动引导。这一每个 AMD 模块对应一个 Angular 子模块的模式让模块间耦合降到最低也天然可测试。页面中对应的ng-controllerTodoController挂载点位于 index.html 的section classtodoapp上。控制器todo.js 的状态管理与事件处理js/controllers/todo.js 采用 AngularJS 惯用的数组式依赖注入字符串参数名 函数声明注入$scope、$location、todoStorage、filterFilterreturn [$scope, $location, todoStorage, filterFilter, function ($scope, $location, todoStorage, filterFilter) { var todos $scope.todos todoStorage.get(); $scope.newTodo ; $scope.editedTodo null; $scope.$watch(todos, function () { $scope.remainingCount filterFilter(todos, { completed: false }).length; $scope.doneCount todos.length - $scope.remainingCount; $scope.allChecked !$scope.remainingCount; todoStorage.put(todos); }, true); // ... } ];控制器承担的职责可以归纳为四类数据初始化从todoStorage.get()读取 localStorage 中的待办列表自动统计与持久化用$scope.$watch(todos, ..., true)第三个参数true表示深度监听监听数组变化每次增删改都重新计算remainingCount剩余未完成数、doneCount、allChecked并调用todoStorage.put(todos)写回 localStorage路由过滤监听$location.path()根据#/、#/active、#/completed把statusFilter设为null、{ completed: false }或{ completed: true }配合模板中的ng-repeattodo in todos | filter:statusFilter track by $index见 index.html实现三种视图切换业务事件addTodo新增空标题被过滤、editTodo进入编辑态并用angular.copy克隆原数据以便回滚、doneEditing提交编辑空标题自动删除、revertEditing按 Esc 回滚、removeTodo、clearDoneTodos、markAll。值得注意的细节revertEditing通过todos[todos.indexOf(todo)] $scope.originalTodo用克隆的原始对象还原条目实现了编辑取消功能。自定义指令todoFocus 与 todoEscape为了让编辑体验符合 TodoMVC 规范双击进入编辑、编辑框自动聚焦、Esc 取消示例实现了两个高内聚指令均采用AMD 模块独立声明 Angular 子模块的写法各自返回模块名供app.js引用。todoFocusjs/directives/todoFocus.js当绑定的表达式为真时把焦点放到元素上。核心是利用$watch$timeout(..., 0, false)在 DOM 更新后执行elem[0].focus()第三个参数false表示不触发$digest避免多余脏检查scope.$watch(attrs.todoFocus, function (newval) { if (newval) { $timeout(function () { elem[0].focus(); }, 0, false); } });模板中对应todo-focustodo editedTodoindex.html即当当前条目处于编辑态时聚焦输入框。todoEscapejs/directives/todoEscape.js捕获 Esc 键keyCode 27并求值绑定的表达式用scope.$apply确保表达式求值进入 Angular 的 digest 循环同时通过scope.$on($destroy, ...)解绑事件避免指令销毁后遗留监听器elem.bind(keydown, function (event) { if (event.keyCode ESCAPE_KEY) { scope.$apply(attrs.todoEscape); } }); scope.$on($destroy, function () { elem.unbind(keydown); });模板中对应todo-escaperevertEditing(todo)实现按 Esc 取消编辑并回滚。服务todoStorage 与 localStorage 持久化js/services/todoStorage.js 用factory注册了一个极简但完整的存储服务Storage 键名为todos-angularjs-requirejs.factory(todoStorage, function () { var STORAGE_ID todos-angularjs-requirejs; return { get: function () { return JSON.parse(localStorage.getItem(STORAGE_ID) || []); }, put: function (todos) { localStorage.setItem(STORAGE_ID, JSON.stringify(todos)); } }; });get在无数据时回退为空数组|| []保证首次访问不会因null而崩溃put将数组序列化后写入。控制器通过深度$watch自动触发put实现了修改即保存的响应式持久化——无需任何手动保存调用。单元测试闭环Jasmine RequireJS 模板readme 中的npm test并非空架子测试用例真实存在于 test/unit/directives/todoEscapeSpec.js。以todoEscape的测试为例它演示了指令级测试的完整套路用define([...])以 AMD 方式加载被测指令、jQuery 与angular-mocksbeforeEach(module(todoEscapeDir))注册被测模块通过inject(function ($rootScope, $compile, $browser) {...})拿到测试所需的 Angular 服务构造指令元素angular.element(input todo-escapedoSomething())并compile(el)(scope)编译链接用 jQuery 合成keydown事件并triggerHandler断言绑定表达式被正确求值triggerKeyDown(el, 27); expect(someValue).toBe(true);这一用例直接验证了Esc 键触发表达式求值的核心契约也让todoEscape指令的内部逻辑有了可回归保障。todoFocusSpec.js同理验证聚焦行为。测试之所以能在 RequireJS 环境下运行完全依赖 test/gruntfile.js 中grunt-template-jasmine-requirejs的templateOptions配置复用../js/main.js的全局配置、baseUrl指向../js、并为测试补充jquery、angular-mocks两个paths同时用shim声明angular-mocks依赖angular。这套复用运行时配置 注入测试依赖的做法是保证测试环境与真实环境一致性的关键。小结从 readme.md 的两个命令出发这个示例完整展示了 AngularJS 与 RequireJS 协作的四个层次配置层main.js的 paths/shim/deps、引导层app.js的手动 bootstrap、业务层控制器 指令 服务的 AMD 化拆分、测试层Jasmine RequireJS 模板复用运行时配置。其中每个 AMD 模块返回独立 Angular 模块名、由入口统一装配以及测试配置复用生产配置两个模式尤其值得在大型 AngularJS 1.x 项目中借鉴。原始 readme 还附带了 AngularJS 官方教程、API 参考、开发者指南以及社区文章的指引可作为深入学习 AngularJS 的起点。【免费下载链接】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),仅供参考
返回列表