AngularJS移动开发中的坑汇总
2014-10-28 18:27
120 查看
使用AngualrJs开发移动App已经快半年了,逐渐积累了非常多AngularJS的问题,特别是对于用惯了Jquery的开发人员,转到AngularJS还是须要克服非常多问题的。不像Jquery那样側重DOM操作,AngularJS是以视图模型和双向绑定为核心的。
以下的内容如果你已经了解前端 MVC 概念,并对 AngularJS 有了一定经验,刚開始学习的人读起来可能比較艰深晦涩。本文的总结会涉及部分在移动设备上特有的问题。
在站点Web前端开发中,假设你感到非常难改变习惯,那么考虑从你的网页中移除 jQuery 吧。真的,AngularJS 中的
jQuery 的 ajax 函数,并且 AngularJS 内嵌了 jQLite —— 它内部实现的一个 jQuery 子集,包括了经常使用的 jQuery DOM 操作方法,事件绑定等等。但这并非说用了AngularJS 就不能用 jQuery 了。假设你的网页有加载 jQuery 那么 AngularJS 会优先採用你的 jQuery,否则它会 fall back 到 jQLite。
假设是移动App或移动Web开发,建议不要引入Jquery了,假设实在须要jquery的某些功能,引入Zepto.js吧。只是请相信我,用了AngularJS,你不会须要Jquery的!
须要自己编写 directives 的情况一般是当你使用了第三方的 jQuery 插件。由于插件在 AngularJS 之外对表单值进行更改,并不能即时反应到 Model 中。比如我们用得比較多的 jQueryUI datepicker 插件,当你选中一个日期后,插件会将日期字符串填到
input 输入框中。View 改变了,却并没有更新 Model,由于
然后在 HTML 中引入这个 directive
就是在 HTML 里写自己定义的标签属性,达到插件的作用,有效补充了HTML的功能。这样的声明式的语法扩展了 HTML。建议项目中通用的功能和页面组件,都封装成Directive,方便使用和代码维护。
须要说明的是,有一个 AngularUI 项目提供了大量的 directive 给我们使用,包含 Bootstrap 框架中的插件以及基于
jQuery 的其它非常热门的 UI 组件。 AngularJS 的社区如今非常活跃,生态系统健全。
这是个大坑。假设你去查看 ngOption 生成的
还是要转变观念,AngularJS 已经不再用表单进行数据交互了,而是用 Model。使用 $http 来提交 Model,在 php 中则使用
type='number'时,在移动设备上ng-change方法会失效。
在页面初始化的时候,用户可能会看到 {{ }},然后闪烁一下才出现真正的内容。
解决的方法:
使用 ng-cloak directive 来隐藏它
使用 ng-bind 替代 {{ }}
Controller 不应该直接引用 DOM,而应该控制 view 的行为。比如“假设用户操作了 X,应该发生什么事情”,“我从哪里能够获得 X?”
Service 在大部分情况下也不应该直接引用 DOM,它应该是一个单例(singletons),独立于界面,与 view 的逻辑无关。它的角色仅仅是“做 X 操作”。
DOM 操作应该放在 directives 里面。
你所写的功能非常可能 AngularJS 已经实现了,有一些代码是能够抽象出来复用的,使用更 Angular 的方式。总之就是非常多 jQuery 的繁琐代码能够被替代。
ng-repeat 非常实用。当 Ajax 从server获得数据后,我们常常使用 jQuery (比方上面讲过的样例) 向某些 HTML 容器节点中加入很多其它的元素,这在 AngularJS 里是不好的做法。有了 ng-repeat 一切就变得非常easy了。在你的 $scope 中定义一个数组 (model) 来保存从server拉取的数据,然后使用 ng-repeat 将它与 DOM 绑定就可以。以下的样例初始化定义了 friends 这个 model
2.
ng-show 也非常实用。使用 jQuery 来依据条件控制界面元素的显示隐藏,这非经常见。可是 Angular 有更好的方式来做到这一点。ng-show (以及 ng-hide) 能够依据布尔表达式来决定隐藏和显示。
对于数组或字符串,能够用strXXXX.length控制显示,否则在移动设备上会不正常。
类似的内置 directives 还有 ng-disabled, ng-switch 等等,用于条件控制,语法简洁,都非常强大。
ng-class 用于条件性地给元素加入 class,曾经我们也经经常使用 jQuery 来实现。Angular 中的 ng-class 当然更好用了,样例:
在这里 ng-class 接受一个 object 对象,key 为 CSS class 名,值为 $scope 变量控制的条件表达式,其它类似的内置 directives 还有 ng-class-even 和 ng-class-odd,非常有用。
使用ng-show和ng-if都实现控制页面元素显示的功能,但2者是不同的,ng-if会动态创建DOM,ng-show仅仅是切换已有DOM的显示,相当于设置style="display:none",假设使用before和after等css伪类控制显示效果,可能会出现故障,须要依据情况合理使用ng-show和ng-if。
AngularJS 的双向数据绑定是最令人兴奋的特性了,然而它也不是全能的魔法,在某些情况下你须要做一些小小的修正。
当你使用 ng-model, ng-repeat 等等来绑定一个元素的值时, AngularJS 为那个值创建了一个 $watch,仅仅要这个值在 AngularJS 的范围内有不论什么改变,全部的地方都会同步更新。而你在写自己定义的 directive 时,你须要定义你自己的 $watch 来实现这样的自己主动同步。
有时候你在代码中改变了 model 的值,view 却没有更新,这在自己定义事件绑定中常常遇到。这时你就须要手动调用 scope.$apply() 来触发界面更新。上面 datepicker 的样例已经说明了这一点。第三方插件可能会有 call back,我们也能够把回调函数写成匿名函数作为參数传入$apply()中。
ng-repeat 非常实用,只是它和 DOM 绑定了,非常难在同一个元素上使用其它 directives (比方 ng-show, ng-controller 等等)。
假设你想对整个循环使用某个 directive,你能够在 repeat 外再包一层父元素把 directive 写在那儿;假设你想对循环内部的每个元素使用某个 directive,那么把它放到 ng-repeat 的一个子节点上就可以。
Scope 在 templates 模板中应该是 read-only 的,而在 controller 里应该是 write-only 的。Scope 的目的是引用 model,而不是成为 model。model 就是我们定义的 JavaScript 对象。
Scopes 在 AngularJS 中形成一定的层级关系,树状结构必定有一个根节点。通常我们用不到它,由于差点儿每一个 view 都有一个 controller 以及相相应的自己的 scope。
但偶尔有一些数据我们希望全局应用在整个 app 中,这时我们能够将数据注入 $rootScope。由于其它 scope 都会继承 root scope,所以那些注入的数据对于 ng-show 这类 directive 都是可用的,就像是在本地 $scope 中的变量一样。
当然,全局变量是邪恶的,你必须非常小心地使用 $rootScope。特别是不要用于代码,而只用于注入数据。假设你非常希望在 $rootScope 写一个函数,那最好把它写到 service 里,这样只实用到的时候它才会被注入,測试起来也方便些。
相反,假设一个函数的功能不过存储和返回一些数据,就不要把它创建成一个 service。
对于刚開始学习的人,这个也是个大坑啊。作用域变量的继承是基于javascript原型继承机制的,在使用涉及到作用域的指令如ng-template,ion-modal等时须要特别注意,相关的查找顺序这里就不细说了。
以下的内容如果你已经了解前端 MVC 概念,并对 AngularJS 有了一定经验,刚開始学习的人读起来可能比較艰深晦涩。本文的总结会涉及部分在移动设备上特有的问题。
DOM操作的问题
避免使用 jQuery 来操作 DOM,包含添加元素节点,移除元素节点,获取元素内容,隐藏或显示元素。你应该使用 directives 来实现这些动作,有必要的话你还要编写自己的 directives。在站点Web前端开发中,假设你感到非常难改变习惯,那么考虑从你的网页中移除 jQuery 吧。真的,AngularJS 中的
$http服务非常强大,基本能够替代
jQuery 的 ajax 函数,并且 AngularJS 内嵌了 jQLite —— 它内部实现的一个 jQuery 子集,包括了经常使用的 jQuery DOM 操作方法,事件绑定等等。但这并非说用了AngularJS 就不能用 jQuery 了。假设你的网页有加载 jQuery 那么 AngularJS 会优先採用你的 jQuery,否则它会 fall back 到 jQLite。
假设是移动App或移动Web开发,建议不要引入Jquery了,假设实在须要jquery的某些功能,引入Zepto.js吧。只是请相信我,用了AngularJS,你不会须要Jquery的!
须要自己编写 directives 的情况一般是当你使用了第三方的 jQuery 插件。由于插件在 AngularJS 之外对表单值进行更改,并不能即时反应到 Model 中。比如我们用得比較多的 jQueryUI datepicker 插件,当你选中一个日期后,插件会将日期字符串填到
input 输入框中。View 改变了,却并没有更新 Model,由于
$('.datepicker').datepicker();这段代码不属于 AngularJS 的管理范围。我们须要编写一个directive 来让 DOM 的改变即时更新到 Model 里。
var directives = angular.module('directives', []); directives.directive('datepicker', function() { return function(scope, element, attrs) { element.datepicker({ inline: true, dateFormat: 'dd.mm.yy', onSelect: function(dateText) { var modelPath = $(this).attr('ng-model'); putObject(modelPath, scope, dateText); scope.$apply(); } }); } });
然后在 HTML 中引入这个 directive
<input type="text" datepicker ng-model="myObject.myDateValue" />Directive
就是在 HTML 里写自己定义的标签属性,达到插件的作用,有效补充了HTML的功能。这样的声明式的语法扩展了 HTML。建议项目中通用的功能和页面组件,都封装成Directive,方便使用和代码维护。
须要说明的是,有一个 AngularUI 项目提供了大量的 directive 给我们使用,包含 Bootstrap 框架中的插件以及基于
jQuery 的其它非常热门的 UI 组件。 AngularJS 的社区如今非常活跃,生态系统健全。
ngOption 中的 value
这是个大坑。假设你去查看 ngOption 生成的 <select>中的
<option>的选项值(每一个
<option value="xxx">的 value 部分),那绝对是枉费心机。由于这里的值永远都会 是 AngularJS 内部元素的索引,并非你所指定的表单选项值。
还是要转变观念,AngularJS 已经不再用表单进行数据交互了,而是用 Model。使用 $http 来提交 Model,在 php 中则使用
file_get_contents('php://input')来获取前端提交的数据。
Input type='number'的问题
AngularJS有些版本号,当输入框设为 Inputtype='number'时,在移动设备上ng-change方法会失效。
{{ }} 的问题
在页面初始化的时候,用户可能会看到 {{ }},然后闪烁一下才出现真正的内容。解决的方法:
使用 ng-cloak directive 来隐藏它
使用 ng-bind 替代 {{ }}
将界面与业务逻辑分离
Controller 不应该直接引用 DOM,而应该控制 view 的行为。比如“假设用户操作了 X,应该发生什么事情”,“我从哪里能够获得 X?”Service 在大部分情况下也不应该直接引用 DOM,它应该是一个单例(singletons),独立于界面,与 view 的逻辑无关。它的角色仅仅是“做 X 操作”。
DOM 操作应该放在 directives 里面。
尽量复用已有功能
你所写的功能非常可能 AngularJS 已经实现了,有一些代码是能够抽象出来复用的,使用更 Angular 的方式。总之就是非常多 jQuery 的繁琐代码能够被替代。
1. ng-repeat
ng-repeat 非常实用。当 Ajax 从server获得数据后,我们常常使用 jQuery (比方上面讲过的样例) 向某些 HTML 容器节点中加入很多其它的元素,这在 AngularJS 里是不好的做法。有了 ng-repeat 一切就变得非常easy了。在你的 $scope 中定义一个数组 (model) 来保存从server拉取的数据,然后使用 ng-repeat 将它与 DOM 绑定就可以。以下的样例初始化定义了 friends 这个 model<div ng-init="friends = [{name:'John', age:25}, {name:'Mary', age:28}]"> I have {{friends.length}} friends. They are: <ul> <li ng-repeat="friend in friends"> [{{$index + 1}}] {{friend.name}} who is {{friend.age}} years old. </li> </ul> </div>
2. ng-show
ng-show 也非常实用。使用 jQuery 来依据条件控制界面元素的显示隐藏,这非经常见。可是 Angular 有更好的方式来做到这一点。ng-show (以及 ng-hide) 能够依据布尔表达式来决定隐藏和显示。对于数组或字符串,能够用strXXXX.length控制显示,否则在移动设备上会不正常。
类似的内置 directives 还有 ng-disabled, ng-switch 等等,用于条件控制,语法简洁,都非常强大。
3. ng-class
ng-class 用于条件性地给元素加入 class,曾经我们也经经常使用 jQuery 来实现。Angular 中的 ng-class 当然更好用了,样例:<div ng-class="{ errorClass: isError, warningClass: isWarning, okClass: !isError && !isWarning }">...</div>
在这里 ng-class 接受一个 object 对象,key 为 CSS class 名,值为 $scope 变量控制的条件表达式,其它类似的内置 directives 还有 ng-class-even 和 ng-class-odd,非常有用。
ng-show和ng-if的使用场景问题
使用ng-show和ng-if都实现控制页面元素显示的功能,但2者是不同的,ng-if会动态创建DOM,ng-show仅仅是切换已有DOM的显示,相当于设置style="display:none",假设使用before和after等css伪类控制显示效果,可能会出现故障,须要依据情况合理使用ng-show和ng-if。
$watch 和 $apply
AngularJS 的双向数据绑定是最令人兴奋的特性了,然而它也不是全能的魔法,在某些情况下你须要做一些小小的修正。当你使用 ng-model, ng-repeat 等等来绑定一个元素的值时, AngularJS 为那个值创建了一个 $watch,仅仅要这个值在 AngularJS 的范围内有不论什么改变,全部的地方都会同步更新。而你在写自己定义的 directive 时,你须要定义你自己的 $watch 来实现这样的自己主动同步。
有时候你在代码中改变了 model 的值,view 却没有更新,这在自己定义事件绑定中常常遇到。这时你就须要手动调用 scope.$apply() 来触发界面更新。上面 datepicker 的样例已经说明了这一点。第三方插件可能会有 call back,我们也能够把回调函数写成匿名函数作为參数传入$apply()中。
将 ng-repeat 和其它 directives 结合起来
ng-repeat 非常实用,只是它和 DOM 绑定了,非常难在同一个元素上使用其它 directives (比方 ng-show, ng-controller 等等)。假设你想对整个循环使用某个 directive,你能够在 repeat 外再包一层父元素把 directive 写在那儿;假设你想对循环内部的每个元素使用某个 directive,那么把它放到 ng-repeat 的一个子节点上就可以。
Scope的问题
Scope 在 templates 模板中应该是 read-only 的,而在 controller 里应该是 write-only 的。Scope 的目的是引用 model,而不是成为 model。model 就是我们定义的 JavaScript 对象。
$rootScope 是能够用的,只是非常可能被滥用
Scopes 在 AngularJS 中形成一定的层级关系,树状结构必定有一个根节点。通常我们用不到它,由于差点儿每一个 view 都有一个 controller 以及相相应的自己的 scope。但偶尔有一些数据我们希望全局应用在整个 app 中,这时我们能够将数据注入 $rootScope。由于其它 scope 都会继承 root scope,所以那些注入的数据对于 ng-show 这类 directive 都是可用的,就像是在本地 $scope 中的变量一样。
当然,全局变量是邪恶的,你必须非常小心地使用 $rootScope。特别是不要用于代码,而只用于注入数据。假设你非常希望在 $rootScope 写一个函数,那最好把它写到 service 里,这样只实用到的时候它才会被注入,測试起来也方便些。
相反,假设一个函数的功能不过存储和返回一些数据,就不要把它创建成一个 service。
子作用域的原型继承问题
对于刚開始学习的人,这个也是个大坑啊。作用域变量的继承是基于javascript原型继承机制的,在使用涉及到作用域的指令如ng-template,ion-modal等时须要特别注意,相关的查找顺序这里就不细说了。
相关文章推荐
- [转]AngularJS移动开发中的坑汇总
- 移动平台WEB前端开发技巧汇总
- 移动平台3G手机网站前端开发布局技巧汇总
- 上万网友力荐的30份Android移动开发技术文档汇总
- 移动平台3G手机网站前端开发布局技巧汇总
- 移动平台WEB前端开发技巧汇总
- 移动平台3G手机网站前端开发布局技巧汇总(转)
- 【移动开发】Android中三种超实用的滑屏方式汇总(ViewPager、ViewFlipper、ViewFlow)
- 移动平台WEB前端开发技巧汇总
- 【移动开发】Android中三种超实用的滑屏方式汇总(ViewPager、ViewFlipper、ViewFlow)
- 移动Web 开发中的一些前端知识收集汇总
- 移动平台3G手机网站前端开发布局技巧汇总
- 移动平台3G手机网站前端开发布局技巧汇总(转)
- 移动开发:iOS下ffmepg开发的一些参考资料汇总
- 移动平台3G手机网站前端开发布局技巧汇总
- 移动平台3G手机网站前端开发布局技巧汇总
- 移动平台3G手机网站前端开发布局技巧汇总(转)
- 移动平台WEB前端开发技巧汇总
- 【转】移动平台WEB前端开发技巧汇总
- 移动平台WEB前端开发技巧汇总