AngularJS学习
https://www.cnblogs.com/lovesong/p/4870006.html
AngularJS是一个框架,框架决定整个项目的开发套路,以框架为主导。
jQuery是一个函数库,以项目本身为主导。
angularjs是个双向绑定的前端JS框架,其他特性都是围绕它工作的。
它适用于CRUD应用(增加(create)、读取(retrieve)、更新(update)和删除(delete))
双向绑定:
(当模板编译视图,视图发生变化触发数据模型变化,数据模型又会作用于视图。)
angularjs元件:其中controller、directive是最为重要的
module:
作为模块组织者,包含其他angularJS元件
controller:
负责跟view沟通,不处理任何跟DOM有关的工作
PS:当你的controller里面写了DOM操作时,就应该反省代码是否写得有问题了。
directive:
类似于HTML标签,可以定义标签的行为,所有与DOM相关的操作都应该写在这里。
PS:尽量不要DOM操作,但可能还是会需要用到,用到时就要在directive里用。
service:
写可以独立运作的代码(与view无关),共用于元件(例如控制器)之间,不应该处理任何跟DOM有关的工作。后台数据的请求接口
filter:
对数据做一些修理,不应该处理任何跟DOM有关的工作
config:
用来定义路由规则,不应该处理任何跟DOM有关的工作
双向数据绑定:
双向数据绑定是个重要的特性,当view中有数据发生了变化,这个变化会反馈到Model的scope的数据上,而当scope数据发生变化时,view中的数据也会更新到最新的值。
三个方法:
scope重要的方法:$apply,$digest,$watch
1$watch
注册一个watcher,监听scope的数据,当数据变化时候调用回调函数。第一个参数是被监听的数据,第二个参数是回调函数。
2$digest
检查scope中的数据是否发生变化,如果变化则关联到该watcher的回调函数就会被执行。
3$apply
这方法是调用$rootScope.$digest(),在$rootScope开始$digest,随后会访问到所有的children scope中的watchers。$apply()方法有两种形式。第一种会接受一个function作为参数,执行该function并且触发一轮$digest循环。第二种会不接受任何参数,只是触发一轮$digest循环。
PS:angularjs并不直接调用$digest(),而是调用$scope.$apply()
当HTML写下表达式如{{ name }}或ng-model="name"时,angularJS在幕后会为你在scope模型上设置一个watcher,如下:
$scope.$watch( 'name' ,function (newValue , oldValue){ //update the DOM with newValue } );
当页面JS事件触发时,angularJS会监视到并更改scope数据,并自动触发一轮$digest循环,每个关联的watcher的回调函数被执行,最后view被更新。
注意地方
1.有的时候你发现明明scope的数据已经改了,但你发现view并没有更新。
这是因为你可能在setTimeout、异步请求等里面去修改数据,但此时angularJS并不知道数据已经变了,不会帮你调用digest循环,所以你需要手动调用$apply。目前一些指令(例:ng-click、ng-model)以及服务(例$timeout、$http)被调用时会自动触发一次$digest循环,这些就不用手动调用$apply.
setTimeout( function () { $scope.$apply( function () { //wrapped this within $apply $scope.name='lu'; } ) },2000 )
或
setTimeout( function () { $scope.name="lu"; $scope.$apply(); } ,2000);
2.脏检查(Dirty checking)
当一个$direst循环运行时,watchers会被执行来检查scope中的models是否发生了变化,如果发生了变化,那么相应的listener函数就会被执行。在当前的一次循环结束后,它会再执行一次循环用来检查是否有models发生了变化。这就是脏检查(Dirty Checking),它用来处理在listener函数被执行时可能引起的model变化。因此,$digest循环会持续运行直到model不再发生变化,或者$digest循环的次数达到了10次。
PS:$digest循环最少也会运行两次,即使在listener函数中并没有改变任何model
3.监控的表达式不要过于复杂,表达式数量不要太多
4.监听含税内不要有DOM操作,那样会显著降低性能
5.不能互相监听对方会修改的属性,以免形成交叉引用
https://www.cnblogs.com/lovesong/p/4889931.html
angular1.3技巧:
1.ng-repeat多个字段排序的写法:
使用orderBy过滤器,第一个参数是一个数组,表示依次按数组中的属性值进行排序(若按第一项比较的值相等,再按第二项比较),第二个参数是正序还是倒序(默认是正序)。
ng-repeat="groupUser in groupUsers | orderBy : ['isOwner' ,'isAdmin'] : true"
2.ng-include引入HTML片段
使用ng-include,第一个参数是页面的相对地址的字符串。应该注意,是一个字符串,不是ng-expression,所以不要忘了加单引号,否则会发现怎么都引不进这个HTML片段。
<div ng-include="'msgs.html'"></div>
3.ng-bind的$scope对象没有随着数据变化而变化
自己实现的ajax,获取数据后,设置到$scope上,view却没有更新,这其实就是angular双向数据的原因,angular不可预见的scope变化,是不会帮忙刷新view的(例:$.ajax和setTimeout)。解决方法就是,数据设置到$scope上后,手动调用$scope.$apply().
PS:一些指令(例ng-click、ng-model)以及服务(例:$timeout、$http)才会自动刷新view。
4.移动触摸(Touch)事件
angular-touch模块提供了触摸的事件和其他手势ngSwipeLeft、ngSwipeRight。
5.ng-bind-html的内容无法正常的显示在页面中
使用ng-bind-html属性,该属性依赖于$sanitize,也就是需要引入angular-sanitize.js文件。但会发现ng-bind-html的内容无法正常的显示在页面中,这是因为某些标签会被angularjs认为是不安全的自动过滤掉,而为了保留这些标签就需要开启非安全模式。
<div ng-bind-html=" article.content | trustHtml "> </div>
myApp.filter( 'trustHtml' , function ($sce){ return function (input){ return $sce.trustAsHtml(input) } } );
其中$sce是angular自带的安全处理服务,$sce.trustAsHtml(input)返回的是受信任的对象。
6.如何划分一个module
在关系比较密切(业务逻辑)的页面可以划为一个module,因为页面可能存在公用service或template或directive(controller不共用),而这些元件归属于同个module,我们就可以不同页面调用了。而不相关的页面可划分为另一个module,增加代码的清晰度。
7.是否要把工具类弄成service
在弄工程之前,我会考虑到是否要将一些工具类封装成一个service(为了看起来代码统一),但我觉得是没有必要的,因为service是归属于某个模块的,而我们的工具类可能在不同模块都有使用,不归属于某个模块,把工具类当成一个jQuery的库引入即可。
8.配合RequireJS使用
angular没有异步加载模块的功能,所以使用配合RequireJS的效果还不错的。在这里面有些异议的是对于模块定义的地方,是该把一个模块定义成RequireJS的模块还是angular的服务(可以依赖注入),我觉得还是功能归属的问题,如果是全局使用的工具服务,就定义成RequireJS模块,而如果是与模块密切相关的业务逻辑就使用服务。
PS:可在RequireJS的config加上urlArgs,可以避免缓存问题。
urlArgs : "bust="+(new Date()) .getTime() //可用来清理缓存,在部署到生产环境去掉。
9.iframe打开跨域URL时报错
<iframe width="100%" height="100%" ng-src="{{url}}"></iframe>
如果不做处理,上面的跨域URL是打不开的,需要定义白名单。
myApp.config( function ($sceDelegateProvider) { $sceDelegateProvider.resourceUrlWhitelist([ // Allow same origin resource loads. 'self', // Allow loading from our assets domain. Notice the difference between * and **. 'https://link.bingosoft.net/**' ]); });
10.使用其他Controller的scope的属性方法
****原作者声明:
我并不清楚我的用法是否恰当,使用其他Controller的scope局限于其parent scope,而不是任何Controller的都可以访问。scope有个属性$parent,通过这个属性可以找到某一层controller的scope。
var parentScope=$scope.$parent.$parent.$parent
PS:多少层$parent是我打印scope对象找出来的
11.form表单的自动提交功能
在输入框点击回车时,angularjs会默认触发第一个button的click事件。
注意:
ng-options的value值的类型是number,当list.id是string类型时无法循环。
ng-repeat的value值的类型是string,当list.id是number类型时无法循环。
合适的案例:
var optItems1 = [{id:1,text:'武汉'},{id:2,text:'北京'},{id:3,text:'杭州'}];
var optItems2 = [{id:'1',text:'武汉'},{id:'2',text:'北京'},{id:'3',text:'杭州'}];
<select ng-model="query.city" ng-options="x.id as x.text for x in optItems1">
<option value=""></option>
</select>
<select ng-model="query.city">
<option value=""></option>
<option ng-repeat="x in optItems2" value="{{x.id}}">{{x.text}}</option>
</select>