使用 AngularJS 从零构建大型应用 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a Javascript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
Javascript 权威指南第 5 版
Closure: The Definitive Guide
seem
V2EX    Javascript

使用 AngularJS 从零构建大型应用

  seem 2015-02-03 22:16:49 +08:00 14618 次点击
这是一个创建于 3904 天前的主题,其中的信息可能已经有所发展或是发生改变。
  • 0、导言
  • 1、准备工作
  • 2、构建框架
  • 3、丰富你的directives
  • 4、公用的services
  • 5、用controllers组织业务

导言

纵览线上各种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 的应用是时候跑起来了。
应用代码展示

一个实际的案例看起来总是要比教程复杂些。下面是项目启动后友好速搭店铺后台的概貌。
店铺后台

什么?不是说好的从零开始构建吗?怎么就跑起来了?
好吧,请把上面这个预览图当做设计稿。我们开始构建框架。

构建框架

根据设计,从结构上将页面划分为

顶部 <div class='fw-topbar' ng-cOntroller='TopbarController'></div>
导航 <ys-navigation ng-cOntroller='ysNavigationController' ng-show='initDone'></ys-navigation>
内容 <div class='fw-main-content' id='main_cnt' ng-view=''></div>
导航的点击会改变浏览器当前的url,内容区域渲染对应模块的内容。

下面开始配置angularJS,来达到上面的目标。
在 js/app.js 配置 YeeshopManager 这个 module,并将它的引用赋值到全局变量YeeshopManagerModule,方便后续继续对其进行配置。
配置module

为了方便管理众多directives与services。我们分别创建了
js/directives.js 集合所有directives的module - YeeshopManager.directives
配置directives

js/services.js 集合所有services的module - YeeshopManager.services
配置services

接下来,配置应用为不同路径的请求调用对应的 controller与模板
在 config/Route.js 中先定义好的规则
配置Route.js

在 config/RouteProvider.js 中配置 $routeProvider
配置$routeProvider

当我们使用 #/guide 路径访问友好速搭店铺后台的新手引导页面的时候,
ngview
ngRoute将为这个index文件上带有ng-view的节点渲染对应的模板 guide.html 并且运行对应的 GuideController。

结构上划分的三个区域对应的controller的关系
顶部 -> TopbarController
导航 -> ysNavigationController
内容 -> 由ngRoute动态的根据当前url和配置,加载对应模块的内容。
至此,大体的结构已经完成。

每个Controller创建的$scope都能独立很好的运行,但有时$scope之间也需要通讯。这时,我们需要为$rootScope配置一个方法,来完成这个工作。

在 config/OnRootScope.js 中配置 $rootScope
配置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的配置。

丰富你的directives

框架构建完成了,参考第二节中的设计稿,接下来我们需要为系统添加各种UI组件。比如图标、按钮、下拉菜单、弹窗。依照angularJS创始人Misko Hevery设计的初衷:
“构建UI应该是声明式的。”
那么,我们也设计自己的规则,来声明UI组件:

图标 <ys-ico></ys-ico>
按钮 <ys-btn></ys-btn>
下拉菜单 <ys-dropdown></ys-dropdown>
弹窗 <ys-popupwindow></ys-popupwindow>
……

完成了以上的思(yi)考(yin),我们着手来声明图标组件。
声明图标组件

声明完成后,我们在模板里面进行调用。

<ys-ico type="trade"></ys-ico>

经过angularJS的编译之后输出的节点与实际效果。
图标效果

对于这个通用的自定义标签<ys-ico>,我们习惯用“组件”来称呼他。在angularJS中,称为一个directive。官方文档中的定义请越过山丘 虽然已白了头~~

使用强大的directive。我们可以将系统中需要复用的所有组件、甚至一个复用的行为全部抽象出来。当你需要使用的时候,你只是需要声明他。
例如,一个旋转的图标:

<ys-ico keepRotating type="trade"></ys-ico>

友好速搭项目早期规划的directive
展示

按照需求增加了水印编辑器directive
水印编辑器

方便商户编辑图片,增加了图片编辑器directive
图片编辑器

这时候,前端工程师的问题就来了:“还有多少directives?”
暴走
答:纵观整个项目的生命周期,所有的directive不可能在初始便全部设计并构建好。请在项目进行的过程中,按需的增加或修改、丰富你的directive,不断提升你构建view的效率。

依照上文构建与调用directive的经验。在实际项目中,我们在模块中需要10个ico,那么我们便在其模板中调用十次的<ys-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

各种services为友好速搭店铺后台提供了统一的api接口调用,图像处理,弹层处理,实用工具等。
通过上面的目录,我们可以看到services文件夹下,有定义$Popup的Popup.js。
(简化代码未测试,仅为示例)
service代码

注入到您所需的模块后,愉快的调用吧!

$Popup.modal({text : '弹窗标题'});

用controllers组织业务

一切就绪,开始堆业务代码!
用controllers图片
用controllers代码

裸奔展示到此结束~有劳看官,若有任何错漏~烦请指正~

31 条回复    2015-05-28 15:12:54 +08:00
lavandachen
    1
lavandachen  
   2015-02-03 22:24:55 +08:00
有点厉害
vngmin
    2
vngmin  
   2015-02-03 22:27:56 +08:00
Up+ *(*)*
cloudqq
    3
cloudqq  
   2015-02-03 22:33:36 +08:00
不错哦, 有参考源码不
br00k
    4
br00k  
   2015-02-03 22:36:36 +08:00
收藏以备学习。有demo代码就好了。
loveuqian
    5
loveuqian  
   2015-02-03 22:36:55 +08:00
好文,可是我还没到那个境界看不懂
immjun
    6
immjun  
   2015-02-03 22:43:56 +08:00
不错~
serenader
    7
serenader  
   2015-02-03 23:03:24 +08:00   1
不错,弹窗那个思路挺好的。收藏。
Arrowing
    8
Arrowing  
   2015-02-03 23:14:23 +08:00
不错,高手作品
zzNucker
    9
zzNucker  
   2015-02-03 23:25:15 +08:00
这种应用好是好,让别人临时过来支持需求的时候成本太高了。
Dannytmp
    10
Dannytmp  
   2015-02-03 23:41:24 +08:00
很强啊,有这水平就不搞PHP了
evlos
    11
evlos  
   2015-02-03 23:46:26 +08:00 via iPhone   1
赞,我经常纠结 AngularJS 的文件和代码结构,这个可以作为一个不错的参考。
p2p
    12
p2p  
   2015-02-04 00:02:41 +08:00 via iPhone
这个应用应该还不算大
Phant0m
    13
Phant0m  
   2015-02-04 00:09:40 +08:00   1
赞~ 入门级 很好的例子
fewspider
    14
fewspider  
   2015-02-04 00:20:03 +08:00 via Android
还是不大敢拿AngularJs做大型应用
seem
    15
seem  
OP
   2015-02-04 00:55:40 +08:00 via Android
@cloudqq
@br00k
可以参考准备工作第七点的项目地址~
seem
    16
seem  
OP
   2015-02-04 00:56:11 +08:00 via Android
@p2p 恭请这位大大前来友好速搭体验一下~
seem
    17
seem  
OP
   2015-02-04 01:04:17 +08:00 via Android
@zzNucker 临时支持的成本大部分还是在于对现有业务的理解~~
bsbgong
    18
bsbgong  
   2015-02-04 08:44:34 +08:00   1
点赞
R4rvZ6agNVWr56V0
    19
R4rvZ6agNVWr56V0  
   2015-02-04 09:19:31 +08:00
@seem 大神可以推荐本书不,俺想尽快入门呢
heaton_nobu
    20
heaton_nobu  
   2015-02-04 09:48:42 +08:00
请问楼主有没有博客,累死的教程还有吗,非常想多学学
heimonsy
    21
heimonsy  
   2015-02-04 09:52:10 +08:00
点赞
seem
    22
seem  
OP
   2015-02-04 10:20:23 +08:00   1
@GeekGao
个人经历:
官方例子+原理看完,ng-app跑起来。
然后更多深入还是要通过项目需求来驱动啦。
p2p
    23
p2p  
   2015-02-04 12:38:44 +08:00
@seem

敢问兄台整套完成 耗时多久
seem
    24
seem  
OP
   2015-02-04 13:29:50 +08:00
@p2p 向大大汇报,至今将近一年~~
ityao
    25
ityao  
   2015-02-04 14:12:21 +08:00
不错, 希望angular越来越多人用, 也欢迎大家体验一下我的angular应用, www.fujin8.com, 微信公众号 附近八
jinzhe
    26
jinzhe  
   2015-02-04 16:26:22 +08:00
文件命名混乱,为啥不都是小写?
seem
    27
seem  
OP
&bsp;  2015-02-04 16:44:13 +08:00
@jinzhe http://trochette.github.io/Angular-Design-Patterns-Best-Practices/ 从此参考延续下来的规则。项目经发布工具打包之后都为小写~谢谢提醒~
fxbird
    28
fxbird  
   2015-02-04 22:33:24 +08:00
我们项目也要用angularjs了
cctrv
    29
cctrv  
   2015-02-05 03:55:56 +08:00
不~ 我也在用 angularjs 。
用 ionic 在公司 App ~ 速度很快的。
macooy
    30
macooy  
   2015-02-05 15:29:06 +08:00
好腻害,学习啦,友好速搭也好强大
sternelee
    31
sternelee  
   2015-05-28 15:12:54 +08:00
好腻害~
关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3485 人在线   最高记录 6679       Select Language
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.8.5 25ms UTC 04:58 PVG 12:58 LAX 21:58 JFK 00:58
Do have faith in what you're doing.
ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86