使用AngularJS这么久以来,遇到过一些坑,之前一直没有以书面的形式整理下,现在好好总结下,以供后面查备。

一、angular scope 在ng-if与ng-show下的区别(两者作用域的差别)

以下代码为一个针对应用列表分页的代码:

HTML代码:

对应的js代码为:

在页面中我们可以看到效果:


可以看到:在使用ng-if时,点击分页时,在ng-if包括的作用域里,$scope.currentPage的值改变了,但是ng-if所在作用域外面,打印$scope.currentPage的值时,仍然不变,始终是初始化的状态,并且可以看到获取的列表也并没有改变。

解决方案:将ng-if换为ng-show,或者ng-model=”currentPage”改为ng-model=”parentObj.currentPage”,下面看看解决之后的效果:



可以看到,选择分页时,页码相应的改变了,获得列表也正确了。

为什么会出现上述情况呢?小编在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的原理是不一样的:

1、ng-show/ng-hide是通过修改CSS样式方式控制元素显示与隐藏,对应的DOM元素会一直存在于当前页面中,而ng-if根据表达式的值动态的在当前的页面中添加删除页面元素。如果赋值表达式的值为false,那么这个元素就会从页面中删除,否则会添加一个元素。ng-if创建元素时用的是被它编译后的代码,如果ng-if内部的代码被其它方式修改过,那么修改只会对本次展现有效,页面元素重新渲染后修改效果会消失,而ng-show/ng-hide则能够保留dom元素上次修改后的状态。

2、作用域不同:当一个元素被ng-if从DOM中删除时,与其关联的作用域也会被销毁。而且当它重新加入DOM中时,则会生成一个新的作用域,而ng-show和ng-hide则不会。

二、UI闪烁问题

众所周知,Angular最大的亮点就是数据的双向绑定。然而,在项目的实际使用过程中,往往会碰到页面闪现出没有被解析的表达式(形如{{app.name}})。是因为在Angular初始化之前,DOM还没准备就绪,Angular正在计算并替换相应的值。

解决办法:

1、放弃使用{{ }}表达式,改用ng-bind指令;

2、在元素上添加“ng-clock”,工作原理就是在初始化阶段inject了css规则,或者你可以包含这个css 隐藏规则到你自己的stylesheet。Angular就绪后就会移除这个cloak样式,让我们的应用(或者元素)立刻渲染。

三、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指令:

四、angularJS文件压缩问题

当项目上线时,我们往往需要将文件压缩以减少体积来提高页面的加载速度,普通的javascript压缩一般都没什么问题,但是如果是以下格式编码的angularJS文件压缩后,在使用则会报错:

解决办法是:使用Javascript数组方式构造控制器:把要注入的服务放到一个字符串数组(代表依赖的名字)里,数组最后一个元素是控制器的方法函数:

varBookCtrl = ['$scope', '$http', function($scope, $http) { /* constructor body */}];

如以下登陆的controller:


这样使用数组的方式在压缩后,就不会出现依赖的错误了。

五、IE11下get请求缓存问题,页面绑定数据不及时更新的bug

在项目开发的过程中,我曾经发现过一个奇葩的问题,就是在IE11浏览器下,当点击某个button触发一个函数,从而改变ng-model绑定的某个变量时,明确变量的值已经改变,但是只有在F12开启开发者调试工具时,页面才能及时更新显示改变后的变量值,一旦F12开发者调试工具关闭,变量值将不更新。但是这一现象在chrome、firefox下确不曾见,究其原因竟是IE浏览器下ajax请求缓存的问题,后来把缓存禁用后,竟恢复正常了。具体解决方法就是:在配置路由的angularJS文件中,添加如下配置代码即可:

六、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重新编译了一遍。

七、使用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是数据的主键值。

八、$apply的使用

之前在微信端修改个人设置的页面时,接口没有返回用户的相关信息,只有通过另一个接口去获取用户的具体信息,但是这个过程中发现拿到用户的具体信息重新给$scope.userData赋值后,虽然model值改变了,但是页面并没有及时更新,主要原因是angular没有检测到数据变化,所以此时需要我们手动通知angular数据改变,如下代码所示:

这里使用的是$apply的无参数形式,另外还有一种形式是:

这样也可以,$scope.$apply() 会自动触发 $rootScope.$digest(),从而让 watchers 被触发用以更新view。具体可以参考这篇文章:深入理解Angular中的$apply()以及$digest()

当然,后面的路还很长,遇到的坑也不止这些,我会持续更新的……

那些年,在AngularJS的路上遇到的坑的更多相关文章

  1. 【转】8年!我在OpenStack路上走过的坑。。。

    8年!我在OpenStack路上走过的坑... 摘要: 2010年10月,OpenStack发布了第一个版本:上个月,发布了它的第18个版本Rocky.几年前气氛火爆,如今却冷冷清清.Rocky版本宣 ...

  2. AngularJS移动开发中的坑汇总

    使用AngualrJs开发移动App已经快半年了,逐渐积累了非常多AngularJS的问题,特别是对于用惯了Jquery的开发人员,转到AngularJS还是须要克服非常多问题的.不像Jquery那样 ...

  3. 关于angularjs在IE里的坑——F12工具打开,功能正常,关闭之后,angularjs not working

    前端时间在做项目的时候,用到了angularjs,期间,发现了一个奇葩的问题,就是在IE11浏览器下,点击下方图1上箭头所示的位置,将此处的开关变为图2中箭头所示的样子,但是发觉没有反应,开关还是灰色 ...

  4. [转]AngularJS移动开发中的坑汇总

    使用AngualrJs开发移动App已经快半年了,逐渐积累了很多AngularJS的问题,特别是对于用惯了Jquery的开发者,转到AngularJS还是需要克服很多问题的.不像Jquery那样侧重D ...

  5. Angularjs里面跨作用域

    Angularjs里面跨作用域的实战!   好久没有来写博客了,最近一直在用Google的AngularJS,后面我自己简称AngularJS就叫AJ吧! 学习AngularJS一路也是深坑颇多啊-- ...

  6. Angularjs里面跨作用域的实战!

    好久没有来写博客了,最近一直在用Google的AngularJS,后面我自己简称AngularJS就叫AJ吧! 学习AngularJS一路也是深坑颇多啊--!就不多说了,不过还是建议大家有时间去学下下 ...

  7. AngularJS常见面试题

    本文引自:https://segmentfault.com/a/1190000005836443 问题来源:如何衡量一个人的 AngularJS 水平? ng-if 跟 ng-show/hide 的区 ...

  8. AngularJS 常见面试问题

    ng-if 跟 ng-show/hide 的区别有哪些? 第一点区别是,ng-if 在后面表达式为 true 的时候才创建这个 dom 节点,ng-show 是初始时就创建了,用 display:bl ...

  9. 关于python数据序列化的那些坑

    -----世界上本来没那么多坑,python更新到3以后坑就多了 无论哪一门语言开发,都离不了数据储存与解析,除了跨平台性极好的xml和json之外,python要提到的还有自身最常用pickle模块 ...

随机推荐

  1. Maltab命令(随用随更新)

    1.eval() ------ 将括号内的字符串视为语句并运行 比如eval('y1=sin(2)')和语句y1=sin(2)等价 多在循环中使用,可以对多个名字有规则的变量或文件进行操作,比如 fo ...

  2. Android--SQLite的使用

    1.熟悉了SQLite的一般用法之后,在实际开发中,为了能够更好的管理和维护数据库,我们会封装一个继承自SQLiteOpenHelper类的数据库操作类,然后以这个类为基础,再封装我们的业务逻辑方法. ...

  3. Scala.js v0.1 发布,在浏览器直接运行 Scala

    今天我们发布了 Scala.js 的首个版本,这个项目是在今年六月份的时候宣布的. 第一个版本支持的特性: 支持所有 Scala 特性,包括宏,不过有一些 语义上的区别 可非常好的跟 JavaScri ...

  4. Dojo动画原理解析

    dojo中动画部分分为两部分:dojo/_base/fx, dojo/fx.dojo/_base/fx部分是dojo动画的基石,里面有两个底层API:animateProperty.anim和两个常用 ...

  5. Javascript自己动手实现getter/setter

    虽然ES5中为我们提供了Object.defineProperty方法来设置getter与setter,但此原生方法使用起来并不方便,我们何不自己来实现一个类,只要继承该类并遵循一定的规范就可以拥有媲 ...

  6. [.net 面向对象程序设计进阶] (4) 正则表达式 (三) 表达式助手

    [.net 面向对象程序设计进阶] (2) 正则表达式(三) 表达式助手 上面两节对正则表达式的使用及.NET下使用正则表达式作了详细说明,本节主要搜集整理了常用的正则表达式提供参考. 此外为了使用方 ...

  7. 【原创】我是怎么从零开始教女同学进行php开发的(4)

    周末给自己放了一个小假,周五晚上跟同学出去吃饭,周六又休息了一天,直到周日才坐到电脑前面码字. 本来说好周末这两天把之前三篇的代码根据评论中的建议好好修改一下的,顺便认真系统地学习一遍HTML基础.结 ...

  8. python property

    python property 在2.6版本中,添加了一种新的类成员函数的访问方式--property. 原型 class property([fget[, fset[, fdel[, doc]]]] ...

  9. Hello Mybatis 01 第一个CRUD

    What's the Mybatis? MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google c ...

  10. java.sql.SQLException: JZ00L

    出现, java.sql.SQLException: JZ00L: 登录失败.检查与此异常现象有关的 SQL 警告以获得失败原因. at com.sybase.jdbc3.jdbc.ErrorMess ...