使用AngularJS这么久以来,遇到过一些坑,以前一直没有以书面的形式整理下,如今好好总结下,以供后面查备。javascript
1、angular scope 在ng-if与ng-show下的区别(二者做用域的差异)php
如下代码为一个针对应用列表分页的代码:css
HTML代码:html
对应的js代码为:java
在页面中咱们能够看到效果:ios
能够看到:在使用ng-if时,点击分页时,在ng-if包括的做用域里,$scope.currentPage的值改变了,可是ng-if所在做用域外面,打印$scope.currentPage的值时,仍然不变,始终是初始化的状态,而且能够看到获取的列表也并无改变。ajax
解决方案:将ng-if换为ng-show,或者ng-model=”currentPage”改成ng-model=”parentObj.currentPage”,下面看看解决以后的效果:chrome
能够看到,选择分页时,页码相应的改变了,得到列表也正确了。数据库
为何会出现上述状况呢?小编在http://camnpr.com/javascript/1888.html和http://stackoverflow.com/questions/21869283/when-to-favor-ng-if-vs-ng-show-ng-hide??这两个地方找到了答案,究其缘由就是ng-if 指令像其它指令同样,会建立一个子域(child scope)。后端
所以,ng-if里的ng-model的$scope是子域下的,外部做用域没法捕获$scope的更新值,而ng-show则是做用于外部做用域的。
综上,ng-if与ng-show的原理是不同的:
一、ng-show/ng-hide是经过修改CSS样式方式控制元素显示与隐藏,对应的DOM元素会一直存在于当前页面中,而ng-if根据表达式的值动态的在当前的页面中添加删除页面元素。若是赋值表达式的值为false,那么这个元素就会从页面中删除,不然会添加一个元素。ng-if建立元素时用的是被它编译后的代码,若是ng-if内部的代码被其它方式修改过,那么修改只会对本次展示有效,页面元素从新渲染后修改效果会消失,而ng-show/ng-hide则可以保留dom元素上次修改后的状态。
二、做用域不一样:当一个元素被ng-if从DOM中删除时,与其关联的做用域也会被销毁。并且当它从新加入DOM中时,则会生成一个新的做用域,而ng-show和ng-hide则不会。
2、UI闪烁问题
众所周知,Angular最大的亮点就是数据的双向绑定。然而,在项目的实际使用过程当中,每每会碰到页面闪现出没有被解析的表达式(形如{{app.name}})。是由于在Angular初始化以前,DOM还没准备就绪,Angular正在计算并替换相应的值。
解决办法:
一、放弃使用{{ }}表达式,改用ng-bind指令;
二、在元素上添加“ng-clock”,工做原理就是在初始化阶段inject了css规则,或者你能够包含这个css 隐藏规则到你本身的stylesheet。Angular就绪后就会移除这个cloak样式,让咱们的应用(或者元素)马上渲染。
3、ng-include指令
<div ng-include="views/include/footer.html"></div> 错在哪里,记得在第一次使用ng-include的时候,这样引用文件,始终在页面上都不显示footer.html的内容,后来明白ng-include须要的是一个变量,因此咱们能够改写成<div ng-include="’views/include/footer.html’"></div> 或定义一个$scope变量,如:$scope.footerHtml="views/include/footer.html"; 页面引用:<div ng-include="footerHtml"></div>。效果以下图所示:
究其缘由是:由于在ng-include中,是把它的参数当作变量来解释的,它会经过$eval对传入的值进行计算,而后做为模板地址去加载。
不过,更好的方法是把这些界面片断(partical)写成指令,那样你就不用在多处重复写路径了,更重要的是,未来你能够直接在这里扩展它的交互逻辑,从界面原型平滑的演化到线上系统。
下面举一个写成指令的例子:
HTML页面:页面中直接使用指令,指令会找到对应的页面进而进行DOM的渲染。
directive指令:
4、angularJS文件压缩问题
当项目上线时,咱们每每须要将文件压缩以减小体积来提升页面的加载速度,普通的javascript压缩通常都没什么问题,可是若是是如下格式编码的angularJS文件压缩后,在使用则会报错:
解决办法是:使用Javascript数组方式构造控制器:把要注入的服务放到一个字符串数组(表明依赖的名字)里,数组最后一个元素是控制器的方法函数:
varBookCtrl = ['$scope', '$http', function($scope, $http) { /* constructor body */}];
如如下登录的controller:
这样使用数组的方式在压缩后,就不会出现依赖的错误了。
5、IE11下get请求缓存问题,页面绑定数据不及时更新的bug
在项目开发的过程当中,我曾经发现过一个奇葩的问题,就是在IE11浏览器下,当点击某个button触发一个函数,从而改变ng-model绑定的某个变量时,明确变量的值已经改变,可是只有在F12开启开发者调试工具时,页面才能及时更新显示改变后的变量值,一旦F12开发者调试工具关闭,变量值将不更新。可是这一现象在chrome、firefox下确未曾见,究其缘由竟是IE浏览器下ajax请求缓存的问题,后来把缓存禁用后,竟恢复正常了。具体解决方法就是:在配置路由的angularJS文件中,添加以下配置代码便可:
6、angular中的unsafe问题
在项目中,以前遇到过这样的问题,就是当给一个ios应用上传安装包和plist文件后,通常这个ios应用的下载地址就会变为:
“itms-services:///?action=download-manifest&url=https://dn-touchc-test.qbox.me/test2.plist”这样的样子,可是当咱们把这样的字符串放到<a>标签的href属性中时,其会自动在上述字符串以前加上“unsafe:”的字符串:以下图所示:
而这个这样加了“unsafe:”字样的连接被咱们复制到手机浏览器里进行下载则会报找不到。
解决办法就是:在angular配置路由的配置文件中加入以下配置代码:
再来看结果:
原来angular对href是有安全检查的,只能生成它认为安全的连接。AngularJS真是为咱们的安全操碎了心……而我也更加明白了{{}}并非一个简单的模板替换,它真的把咱们的html从新编译了一遍。
7、使用ng-repeat或ng-options进行数据循环时,track by的使用
在使用ng-repeat进行数据循环时,若是后端数据库采用的是moogodb的话,当 ng-repeat 的数组被替换时, 它默认并不会从新利用已有的 Dom 元素,而是直接将其所有删除并从新生成新的数组 Dom 元素,Dom 的频繁操做是很是不友好的,为何 ng-repeat 不能利用已有的 dom 元素去更新数据呢?由于你没有把数组元素的标识属性告诉它,那么两次替换的时候它就没办法追踪了,因此当首次使用ng-repeat渲染出列表数据,再次请求渲染数据的时候,ng-repeat会往数组中每一个元素加上$$hashKey属性,这个 key 是由 Angular 内部的 nextUid() 方法生成,相似数据库自增,可是是使用字符串。所以,咱们使用 track by 来避免,例如:
$index表示默认的索引(自动递增),item.id是数据的主键值。
8、$apply的使用
以前在微信端修改我的设置的页面时,接口没有返回用户的相关信息,只有经过另外一个接口去获取用户的具体信息,可是这个过程当中发现拿到用户的具体信息从新给$scope.userData赋值后,虽然model值改变了,可是页面并无及时更新,主要缘由是angular没有检测到数据变化,因此此时须要咱们手动通知angular数据改变,以下代码所示:
这里使用的是$apply的无参数形式,另外还有一种形式是:
这样也能够,$scope.$apply() 会自动触发 $rootScope.$digest(),从而让 watchers 被触发用以更新view。具体能够参考这篇文章:深刻理解Angular中的$apply()以及$digest()。
固然,后面的路还很长,遇到的坑也不止这些,我会持续更新的……