一. 功能使用
1、按功能模块划分而不是MVC结构
尽管有些文章上是推荐MVC结构,但是个人认为这种方法对小项目还可以接受。如果大项目的话,就会显得很臃肿,而且每个js文件都只有一些代码。这样还不如直接按功能模块,将公共的方法抽取到一个公共模块当中,每个功能模块就只对应一个js文件,然后在里面写Controller/service/config等等。
- controller层:不要涉及到太多的业务逻辑,可以将公用的部分抽取到Service层
- service层:主要负责数据交互和数据处理、处理一些业务领域上的逻辑;
- controller层:主要负责初始化$scope的变量用于传递给view层,并且处理一些页面交互产生的逻辑;
- 当一个功能是设计远程API调用、数据集、业务领悟复杂逻辑、将会大量重复的运算方法时就可以考虑将代码以service形式注入controller层。
- controller 里的 $scope 是唯一页面数据来源。不要直接修改 DOM。
- controller 不要在全局范围
- 用 Factory 就是创建一个对象,为它添加属性,然后把这个对象返回出来。你把 service 传进 controller 之后,在 controller 里这个对象里的属性就可以通过 factory 使用了。
- Service 是用"new"关键字实例化的。因此,你应该给"this"添加属性,然后 service 返回"this"。你把 service 传进 controller 之后,在controller里 "this" 上的属性就可以通过 service 来使用了。
- Providers 是唯一一种你可以传进 .config() 函数的 service。当你想要在 service 对象启用之前,先进行模块范围的配置,那就应该用 provider。
- Factory/service是第一个注入时才实例化,而provider不是,它是在config之前就已实例化好
2、模块化、公共化
对于每一个页面可能都会用到的一些公共方法,如果get/post的ajax请求,就可以封装在一个service里面,然后这个service放在公共js文件里,其实页面有需要调用,只需要引入此模块,注入此service.
3、控制Controller层的大小
因为Controller不是单例的,所以每次访问时实例一个,这样会很耗费性能。所以建议是只在此页面上应用的一些公共变量或公共方法可以抽取出来,放在Serivce或者其它。
4、尽量使用AngularJs原生自带的指令、函数等
如果AngularJs自带的指令或函数等不能满足你的要求,个人建议是yi自己来写指令,包括配置等。自己写一方面你可以很方便进行扩展,另一方面维护性也会比较好。建议不要用太多的第三方插件,能用原生就用原生的,不能就自己写,实现不行才考虑第三方AngularJs相关插件。
5、抛弃Jquery
经常看到那种引入了AngularJs而又引Jquery文件,然后代码里头scope和$('#....')到处飞。这样整个js文件就非常乱,你根本就很难来进行调试,而且后面维护的人难度也会加大。完成不符合AngularJs数据驱动的思想,使用了AngularJs,就不要再想Jquery。NO!
6、Anuglar UI bootstap推荐使用
使用Anuglar UI bootstap就相当于只要引入bootstarp的CSS文件,angularjs文件,还有UI bootstap的js文件,你就可以设计出非常好看的界面效果。Anuglar UI bootstap就相当于是一个将bootstarp.js文件用Angular指令的方法重写了。然后你只需要引入bootstarp.css文件即可。
7、数据驱动而不是Dom设计
不要一来就使用类似Jquey的思想,如我要给这个按钮加什么事件。获取什么值。而应该是想这个按钮绑定了什么数据,我应该怎么去变化这个数据即可。不要想着自己去改变Dom,而是应该想着怎么去对数据进行增删改查,绑定到对应的数据。Angulatjs自然会去帮你重新更新Dom元素。
8、使用ng-inspector来调试
其实说是调试,在Angularjs里准确说应该是看数据的变化。这个是一个浏览器插件,可以实时显示当前页面是否使用Anguarljs,以及它当前页面所有的绑定的数据。非常直观
9.用angularjs value、constant 来设置全局变量
二、性能使用篇
1、尽量少用$watch
$watch会非常耗费性能,建议使用ng-change,ng-select来替换。
2、使用ng-bind
不使用{{}},而是ng-bind。一方面可以避免数据未加载完全时页面的闪烁,另一方面g-bind性能也更加好。
3、$rootScope不要绑定太多数据
rootScope就相当是全局变量,绑定多了,不仅可以会和子scope变量冲突,也会引起性能的下降。
4、页面内尽量少用filters
当在页面内的模型后面增加filter时,这个会造成当前模型在$digest里运行两次,造成不必要的性能浪费.第一次在$$watchers检测任务改变时;第二次发生在模型值修改时,所以尽量少用内联时的过滤器语法,像下面这样的非常影响页面性能。
5、注意 ng-if/ng-show的使用
ng-if是移除dom。而ng-show是隐藏dom,所以个人建议是对于大对象dom,建议使用ng-show,对应小对象dom,建议使用ng-if;
6、Scope不超过2000个
有一些文章上说Scope超过2000个后,AngualrJs性能会急速下降,这个观点个人没做过验证,不敢做担保。
7、 过滤器(Filters)
要尽量避免使用过滤器。他们会在每个更新周期运行两次,每当发生任何改变时运行一次,另一次是收集更深层次的改变时触发。所以不要直接从内部列表中移除对象,使用CSS控制即可。(注* 用添加CSS类名去隐掉他们)渲染时的 $index 值并不是真正的数组索引值,它豪无价值。但是排好序的数组索引,无法让你遍历到所有列表中的域。
8、 更新 ng-repeat
当使用ng-repeat时要尽量避免对全局列表的刷新。ng-repeat会产生一个$$hashkey属性和一系统唯一的项。这意味着当你调用 scope.listBoundToNgRepeat = serverFetch() 时会引起对整个列表的重新刷新。会通知执行所有的watchers并触发每一个元素,这是非常消耗性能的。这里有两种解决方案。一种是维护两个集合,和带有过虑器(filter)的ng-repeat(基本上需要自定义同步逻辑,因此算法更复杂,可维护性更差),另一种方案是使用track by去指定你自己的key(Angular 1.2 开始支持,只需要很少的同步逻辑)。
9、 $digest() 和 $apply()
scope.$apply 是一个强大的工具,可以让你向Angular引入外部的值。本质上它会触发Angular的所有事件(例如ng-click)。问题是scope.$apply会从根域$rootScope开始,遍历所有的域链,触发每一个域。scope.$digest只会执行指定域及其相关的域。两种性能差异不言自明。折中的方案是,不触发任何域等到下一个更新周期再更新。
10、 $on, $broadcast 和 $emit
$emit只能向parent controller传递event与data
$broadcast只能向child controller传递event与data
$on用于接收event与data
像$watch一样,他们都是一些很慢的事件,(有可能)遍历整个作用域。他们可能像GOTO一样,让你的程序无法调试。不过幸运地是像$watch一样,他们都可以在完全不需要的时侯解绑。比如在 $on('$destroy')中。
11、 $destroy
像前面提到的那样,你应该在$on('$destroy')中解绑你所有的事件侦听器,取消任何$timeout的实例,或者任何其它异步执行的交互。这不仅仅是确保安全。还可以让你的域更快地被垃圾回收。不这样做,他们会一直在后台运行。直接你清空CPU和RAM。另外,解绑DOM上的事件侦听器也非常重要,不这样做很可能在老式浏览器中引起内存泄露。
12、 $evalAsync
scope.$evalAsync是一个强大的工具。它可以在当前域中执行,并不触发域的更新。evalAsync可以极大地提高你网页的性能。
13、编绎周期
指令(Directive)的compile函数是在域被附加前操作DOM的完美功能(比如说绑定事件)。一个很重要的性能方面是,传入compile函数的元素和属性以原始html模板呈现。只会被运行一次,接下来会直接使用。另外一个重要的点是prelink和postlink的区别。prelink从外向内执行。postlinks从内向外执行。prelink性能稍好一些,因为它不会产生第二次更新周期。但是这时子元素的DOM还未被创建。
14、ng-repeat多个字段排序的写法
使用orderBy过滤器,第一个参数是一个数组,表示依次按数组中的属性值进行排序(若按第一项比较的值相等,再按第二项比较),第二个参数是正序还是倒序(默认是正序)。ng-repeat="groupUser in groupUsers | orderBy:['isOwner','isAdmin']:true"
15、ng-include引入HTML片段
使用ng-include,第一个参数是页面的相对地址的字符串。应该注意,是一个字符串,不是ng-expression,所以不要忘了加单引号,否则会发现怎么都引不进这个HTML片段。<div ng-include="'msgs.html'"></div>
16、关于ng-bind-html
通常情况下为html元素绑定数据,有ng-bind就够了,但一些情境下需要绑定的不是一般的数据,而是html.那么ng-bind就不够用了,需要使用ng-bind-html,它会将内容作为html格式输出.比如想输出带有class的html,那么就使用ng-bind-html,而且还需要ngSanitize的配合,需要引入相应的文件.
三、AngularJs常用插件与模块
注:以下很多网站都需要翻墙才能访问
gitHub实时更新:https://github.com/appleappleapple/AngularJsLearning
1、AngularJs
GitHub:https://github.com/angular/angular.js
英文API:https://docs.angularjs.org/tutorial
国内:https://angularjs.org/
中文入门:http://www.apjs.net/
第三方Module:http://ngmodules.org/
Angular-UI AngularJs的一些UI模块插件
网址:http://angular-ui.github.io/
Angular-UI Bootstarp 用Angular指令来操作Bootstarp的控件
GitHub:https://github.com/angular-ui/bootstrap
API教程:https://angular-ui.github.io/bootstrap/
AngularStrap 用Angular指令来操作Bootstarp的控件
GitHub:https://github.com/mgcrea/angular-strap
教程:http://mgcrea.github.io/angular-strap/
AngularJs 全局页面切换动画 me-pageloading
Github: https://github.com/jeremial/me-pageloading
2、做好的demo效果
配合 angular-ui-router使用, 效果http://isay.me/me-pageloading/angular-ui-router.html
配合 angular-route使用, 效果http://isay.me/me-pageloading/angular-route.html
3、AngularJs loading效果插件
(1)angular-http-loader
GitHub:https://github.com/wongatech/angular-http-loader
效果:http://tech.wonga.com/angular-http-loader/
(2)angular-loading-bar
GitHub:https://github.com/chieffancypants/angular-loading-bar
效果:http://chieffancypants.github.io/angular-loading-bar/
4、AngularJs 文件上传
(1)ui-uploader
Github:https://github.com/angular-ui/ui-uploader
(2)Angular Tree
GitHub:https://github.com/wix/angular-tree-control
API:http://wix.github.io/angular-tree-control/
http://www.jq22.com/jquery-info5757
http://jsfiddle.net/eu81273/8LWUc/18/
http://angularscript.com/collection/tree-view/
(3)angular-tree-dnd
http://thienhung1989.github.io/angular-tree-dnd/demo/#/basic
(4)Angular UI Tree
https://github.com/angular-ui-tree/angular-ui-tree
效果:http://angular-ui-tree.github.io/angular-ui-tree/#/basic-example
(5)select2 (将select/search/input结合使用)
GitHub:https://github.com/angular-ui/ui-select2
效果展示:http://showcase.ngnice.com/#/select/select2
(6)AngularJs MultiSelect – 多选下拉菜单的AngularJS指令
GitHub:https://github.com/isteven/angular-multi-select
效果展示:http://isteven.github.io/angular-multi-select/#/main
(7)ui-select
GitHub:https://github.com/angular-ui/ui-select
效果展示:http://angular-ui.github.io/ui-select/#examples
(8)chose
http://leocaseiro.github.io/angular-chosen/
gitHub实时更新:https://github.com/appleappleapple/AngularJsLearning
四、angularjs 路由
1、路由一般主要通过两个方法:
when():配置路径和参数;
otherwise:配置其他的路径跳转,可以想成default。
2、when的第二个参数:
controller:对应路径的控制器函数,或者名称
controllerAs:给控制器起个别名
template:对应路径的页面模板,会出现在ng-view处,比如"<div>xxxx</div>"
templateUrl:对应模板的路径,比如"src/xxx.html"
resolve:这个参数着重说下,该属性会以键值对对象的形式,给路由相关的控制器绑定服务或者值。然后把执行的结果值或者对应的服务引用,注入到控制器中。如果resolve中是一个promise对象,那么会等它执行成功后,才注入到控制器中,此时控制器会等待resolve中的执行结果。
redirectTo:重定向地址
reloadOnSearch:设置是否在只有地址改变时,才加载对应的模板;search和params改变都不会加载模板
caseInsensitiveMatch:路径区分大小写
3、路由有几个常用的事件
$routeChangeStart:这个事件会在路由跳转前触发
$routeChangeSuccess:这个事件在路由跳转成功后触发
$routeChangeError:这个事件在路由跳转失败后触发
4、使用注意事项
(1)引入angular-route.js文件
(2)引入ngRoute模块, angular.module("myApp",["ngRoute"])
(3)页面设置 <div ng-view ></div><!--这里就是渲染其他视图的地方-->
(4)定义路由的页面,可以用<script type='text/ng-template' id='...'><script>包围
5、absUrl
absUrl() 方法用来获取编码后的完整URL:$location.absUrl()
6、 hash()
hash() 方法用来获取URL中的hash片段:$location.hash(); // 返回当前的hash片段
7、 host()
$location.host();// 当前URL的主机
8、 port()
port() 方法用来获取URL中的端口号:$location.port();// 当前URL的端口
9、protocol()
protocol() 方法用来获取URL中的协议:$location.protocol();// 当前URL的协议
10、 search()
search() 方法用来获取URL中的查询串:$location.search();
五、全局变量
使用rootscope,笔者的建议是放在run中,这里其这controller中都不用引入rootscope,直接使用需要的全局变量就可以了。
每个Controller层都会先在当前的scope找需要的变量,找不到,再到rootscope上去寻找。如果还是找不到,就会报错。
value与constant区别
value不可在config里注入,constant可以。
在ng-app或控制器中定义的全局变量,在不同的controller里都可以使用。
1、通过var 直接定义global variable,这根纯js是一样的。
var test2 = 'tank'; //方法1定义全局变量
2、用angularjs value来设置全局变量 。
app .value('test',{"test":"test222","test1":"test111"}); //方法2定义全局变量
3、用angularjs constant来设置全局变量 。
app .constant('constanttest', 'this is constanttest'); //方法3定义全局变量
4、用angularjs rootscope来设置全局变量 。
5、定义服务。
6、$rootScope。
7、定义一个服务 来传 值:
不同controller之间传值,profile是自定义的一个服务!