捂脸,辛酸泪ing......

本文主要涉及部分在移动设备上特有的问题。

相对来说,Jquery侧重DOM操作,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有些版本,当输入框设为 Input type='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 从服务器获得数据后,我们经常使用 jQuery (比如上面讲过的例子) 向某些 HTML 容器节点中添加更多的元素,这在 AngularJS 里是不好的做法。有了 ng-repeat 一切就变得非常简单了。在你的 $scope 中定义一个数组 (model) 来保存从服务器拉取的数据,然后使用 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等时需要特别注意,相关的查找顺序这里就不细说了。

PS:如果有写错的地方,欢迎指出,谢谢。

AngularJS移动开发中的各种坑的更多相关文章

  1. 总结微信小程序开发中遇到的坑

    总结微信小程序开发中遇到的坑,一些坑你得一个一个的跳啊,/(ㄒoㄒ)/~~ 1,页面跳转和参数传递实例 首先说一下我遇到的需求有一个我的消息页面,里面的数据都是后端返回的,返回的数据大致如下,有一个是 ...

  2. celery开发中踩的坑

    celery开发中踩的坑 celery连接redis 当使用redis做broker,redis连接需要密码时: BROKER_URL='redis://:xxxxx@127.0.0.1:6379/0 ...

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

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

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

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

  5. 【EasyUI总结】EasyUI开发中遇到的坑

    普遍: 1.easyui在书写键值对的时候要注意是否要加引号,在需要加引号的地方不加则无法渲染: datagrid数据网格: 1.datagrid默认请求方式是post,如果要使用分页功能pagina ...

  6. 关于ionic开发中遇到的坑与总结

    这次是第二次使用ionic开发混合app,今天算是对这个框架做一个总结,基础的我就不再重复了,网上都有教程.我就说说自己的心得和遇见的各种坑, 之后会陆续补充,想到什么说什么吧. 1.关于ionic效 ...

  7. ionic开发中的各种坑

    提前说明:这些坑是ionic1的. 一.关于缓存:<ion-view>中设置cache-view="false"表示禁用缓存,默认为true; 二.列表进入详情页面后返 ...

  8. TFS扩展开发中遇到的坑

    本码农最近开发一个VS扩展,其中有些功能涉及到文件的签出.我们公司用的是TFS,遇到了一些奇特的现象,将解决过程记录如下. 一.明明在线的连接却Offline属性等于True public stati ...

  9. 那些在django开发中遇到的坑

    1. 关于csrf错误 CSRF(Cross-site request forgery)跨站请求伪造,也被称为“one click attack”或者session riding,通常缩写为CSRF或 ...

随机推荐

  1. Java对象大小计算

    这篇说说如何计算Java对象大小的方法.之前在聊聊高并发(四)Java对象的表示模型和运行时内存表示 这篇中已经说了Java对象的内存表示模型是Oop-Klass模型. 普通对象的结构如下,按64位机 ...

  2. C++-Qt【4】-CheckBox on QListView

    引用:http://www.qtcentre.org/threads/47119-checkbox-on-QListView QListWidgetItem *item = new QListWidg ...

  3. 《转》Unity3D研究院之UGUI一个优化效率小技巧

    无意间发现了一个小技巧.如下图所示,可以发现UGUI的Image组件的RaycastTarget勾选以后会消耗一些效率,为了节省效率就不要勾选它了,不仅Image组件Text组件也有这样的问题. 一般 ...

  4. Problem of saving images in WPF (RenderTargetBitmap)zz

      To save a visual to an image file need to use RenderTargetBitmap, detail is reference to Save and ...

  5. Mac锁屏

    http://www.dbform.com/html/2006/192.html 应用程序-实用工具-钥匙锁-菜单栏中的钥匙串访问-偏好设置-选中“在菜单栏中显示钥匙串”

  6. 【BZOJ3172】[Tjoi2013]单词 AC自动机

    [BZOJ3172][Tjoi2013]单词 Description 某人读论文,一篇论文是由许多单词组成.但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次. Input ...

  7. js学习笔记 (继续)

    转义字符不断行的空白格 nbsp:1 2半方大的空白 ensp 1 2全方大的空白 emsp 1 2小于号 < <大于号 > >双引号 " "AND符号 & ...

  8. Android应用-听听

    听听是一款记歌词音乐播放器android应用. 功能特点:1.搜索网络歌词.2.本地音乐分类播放.3.离线保存网络歌词.4.页面整洁干净,风格清新. 下载APP 屏幕截图:        

  9. View的滑动

    View的滑动 通过三种方式可以实现View的滑动: 1.通过View本身提供的scrollTo/scrollBy方法来实现滑动 2.通过动画给View施加平移效果来实现滑动 3.通过改变View的L ...

  10. wex5中的星星评分

    新建一个空白的.w文件,然后在页面上放5个img星星图片 重要的是图片路径不能是绝对路径,要用相对路径,不然js操作的时候会出bug 添加两个label标签(标签随你挑,在这我就用label) 你到时 ...