纵览线上各种 AngularJS 教程,大部分都是基础与一些技巧分析。
如果你已经能运行你的 ng-app,但又找不到实际案例可以参考。那么本文应该对您有所帮助。
本文将以电商产品:友好速搭 其中的 店铺后台 作为的实际案例,裸奔展示如何从零构建 “自以为大型的” AngularJS 应用。
应用基于 AngularJS 1.2.24 版本。
1、我们使用了以类型优先的目录结构。 ├── js │ ├── app.js │ ├── directives.js │ ├── services.js │ ├── controllers │ │ ├── BaseController.js // controller 基类 │ │ ├── Customer.js // 顾客管理 │ │ ├── Product.js // 商品管理 │ │ ├── Order.js // 订单管理 │ │ ├── Domain.js // 域名管理 │ │ ├── Payment.js // 收款方式 │ │ └── ... // 其他各种 controller │ ├── directives │ │ ├── ysBtn.js // 按钮组件 │ │ ├── ysCalendar.js // 日历组件 │ │ ├── ysImgeditor.js // 图片编辑器 │ │ ├── ysPopWindow.js // 模态弹窗组件 │ │ └── ... // 其他各种组件 │ └── services │ │ ├── Graphic.js // 图片文件处理 service │ │ ├── Popup.js // 弹层 service │ │ ├── Uri.js // 与 Uri 相关操作 service ($http 等 ajax 操作封装于此) │ │ └── ... // 其他各种 service │ ├── config │ │ ├── Navigation.js // 主导航配置 │ │ ├── Route.js // 路由配置 │ │ ├── RouteProvider.js // 配置$routeProvider │ │ ├── OnRootScope.js // 为$rootScope 配置$onRootScope 方法 │ │ ├── SceDelegate.js // 配置$sceDelegateProvider │ │ ├── Uri.js // 后端服务 API 配置 │ │ └── ... // 其他各种 config ├── lib │ ├── bower_components │ │ ├── angular │ │ │ ├── angular.min.js │ │ │ └── ... │ │ ├── angular-route │ │ ├── angular-sanitize │ │ ├── angular-route │ │ └── ... // 其他 bower 管理的 lib │ ├── URI.min.js │ ├── class.js │ └── ... // 其他手动管理的 lib ├── img ├── css └── html // controllers 对应的 views 的模板
2、使用 less 作为 css 的预处理器。 3、使用 bower 管理依赖的 JS 库。 4、使用 grunt 作为项目打包工具。 5、使用 fiddler4 作为 http 请求调试工具。 6、为了可以使用庞大的 jquery 插件库,我们也引入了 jquery。 7、controllers、directives、services 等部分的设计参考自: http://trochette.github.io/Angular-Design-Patterns-Best-Practices/
准备了半天,访问如下的 index 页面,angular 的应用是时候跑起来了。
一个实际的案例看起来总是要比教程复杂些。下面是项目启动后友好速搭店铺后台的概貌。
什么?不是说好的从零开始构建吗?怎么就跑起来了? 好吧,请把上面这个预览图当做设计稿。我们开始构建框架。
根据设计,从结构上将页面划分为
顶部
导航 内容 导航的点击会改变浏览器当前的 url,内容区域渲染对应模块的内容。下面开始配置 angularJS,来达到上面的目标。 在 js/app.js 配置 YeeshopManager 这个 module,并将它的引用赋值到全局变量 YeeshopManagerModule,方便后续继续对其进行配置。
为了方便管理众多 directives 与 services。我们分别创建了 js/directives.js 集合所有 directives 的 module - YeeshopManager.directives
js/services.js 集合所有 services 的 module - YeeshopManager.services
接下来,配置应用为不同路径的请求调用对应的 controller 与模板 在 config/Route.js 中先定义好的规则
在 config/RouteProvider.js 中配置 $routeProvider
当我们使用 #/guide 路径访问友好速搭店铺后台的新手引导页面的时候, ngRoute 将为这个 index 文件上带有 ng-view 的节点渲染对应的模板 guide.html 并且运行对应的 GuideController。
结构上划分的三个区域对应的 controller 的关系 顶部 -> TopbarController 导航 -> ysNavigationController 内容 -> 由 ngRoute 动态的根据当前 url 和配置,加载对应模块的内容。 至此,大体的结构已经完成。
每个 Controller 创建的$scope 都能独立很好的运行,但有时$scope 之间也需要通讯。这时,我们需要为$rootScope 配置一个方法,来完成这个工作。
在 config/OnRootScope.js 中配置 $rootScope 使用$provide 的 decorator 方法在$rootScope 注册的时候,注入一个 $onRootScope 的方法。
需要被通知的$scope 调用 $onRootScope 来监听事件'notification', 发出通知的 controllers, directives,或 services 中,只需要注入 $rootScope 服务。就可以很方便的进行通知。
友好速搭 作为一款 SAAS 产品,支持商家自行绑定域名,让用户更好的记住您的域名和品牌。
angularJS 构建的应用程序,需要将静态资源部署在 CDN 上,来保证用户访问的快速流畅。 那么,如果我绑定了 http://myshop.com/ ,店铺后台的地址就会是 http://myshop.com/admin, 这时 CDN 静态资源的地址会是形如 http://cdn.com/js/app.js。 当应用的 host http://myshop.com/ 和引用资源的 host http://cdn.com/ 不一致时, angular 会告诉你 Error: [$sce:insecurl] ,资源因安全策略而加载失败。
配置资源白名单$sceDelegateProvider.resourceUrlWhitelist,允许 angular 跨域请求指定的 url 的资源。
至此,我们完成对 YeeshopManagerModule 的配置。
框架构建完成了,参考第二节中的设计稿,接下来我们需要为系统添加各种 UI 组件。比如图标、按钮、下拉菜单、弹窗。依照 angularJS 创始人 Misko Hevery 设计的初衷: “构建 UI 应该是声明式的。” 那么,我们也设计自己的规则,来声明 UI 组件:
图标 按钮 下拉菜单 弹窗 ……
完成了以上的思 (yi) 考 (yin),我们着手来声明图标组件。
声明完成后,我们在模板里面进行调用。
<ys-ico type="trade"></ys-ico>
经过 angularJS 的编译之后输出的节点与实际效果。
对于这个通用的自定义标签,我们习惯用“组件”来称呼他。在 angularJS 中,称为一个 directive。官方文档中的定义请越过山丘 虽然已白了头~~
使用强大的 directive。我们可以将系统中需要复用的所有组件、甚至一个复用的行为全部抽象出来。当你需要使用的时候,你只是需要声明他。 例如,一个旋转的图标:
<ys-ico keepRotating type="trade"></ys-ico>
友好速搭项目早期规划的 directive
按照需求增加了水印编辑器 directive
方便商户编辑图片,增加了图片编辑器 directive
这时候,前端工程师的问题就来了:“还有多少 directives?” 答:纵观整个项目的生命周期,所有的 directive 不可能在初始便全部设计并构建好。请在项目进行的过程中,按需的增加或修改、丰富你的 directive,不断提升你构建 view 的效率。
依照上文构建与调用 directive 的经验。在实际项目中,我们在模块中需要 10 个 ico,那么我们便在其模板中调用十次的标签。
那么前端工程师的问题又来了:“如果模块的交互需要弹窗,难不成我要先算好有多少个?然后全部先在模块里面声明,并使用 ng-show="false"全部隐藏起来?”
Don't worry.不要被 Thinking-in-AngularJs 限制了您的思维。换一个姿势 Thinking in jquery。 当我们需要一个弹窗的时候,按照往常的做法,便是在你页面架构预设好的位置(例如页面底部),插入弹窗的 dom 结构。 没错,弹窗还是这样实现,不同的是。我们插入的是弹窗的 directive。 类似以下(简化代码未测试,仅为示例):
$('body').append($compile('<ys-popwindow data="PopupModalData">#{content}</ys-popwindow>')($scope));
我们通过动态插入 directive 解决了上面这个问题。但我总不能每个模块都写弹窗 dom 的插入吧。 这个时候,我们需要 service。
各种 services 为友好速搭店铺后台提供了统一的 api 接口调用,图像处理,弹层处理,实用工具等。 通过上面的目录,我们可以看到 services 文件夹下,有定义$Popup 的 Popup.js。 (简化代码未测试,仅为示例)
注入到您所需的模块后,愉快的调用吧!
$Popup.modal({text : '弹窗标题'});
一切就绪,开始堆业务代码!
裸奔展示到此结束~有劳看官,若有任何错漏~烦请指正~