今年3月接触AngularJs,并且在6月的项目中开始应用,从踩坑到填坑花了不少时间,根据项目中的实际应用情况总结了一些经验,如下:

一.UI控件选择

Angularjs是不缺控件的,Github里现成的控件非常丰富,基本上足以应付一个普通管理系统中常见的控件需求。但是控件的丰富会带来选择的困难。选择控件要满足几个原则:
原则1:符合业务场景
原则2:控件持续更新
原则3:满足性能要求

举几个例子。首先是上传附件的控件。项目中要用到附件上传,谷歌上搜到了三个控件,分别是
https://github.com/leon/angular-upload
https://github.com/danialfarid/ng-file-upload
https://github.com/nervgh/angular-file-upload

因为项目需要兼容IE9,就重点关注了这三个控件对浏览器的兼容性。第一个控件没有任何说明,第二个控件支持IE9,但是前提是要安装flash,第三个控件支持IE8和9,但是只支持部分功能。从浏览器兼容性的角度考虑,最终选择了控件三。

再举一个例子,下拉框控件。html原生的select功能比较单一,并且option的样式很难修改,在前端各个框架所用的下拉框基本上都是重新实现的。Angularjs也不例外。项目中刚开始选用了ui-select2。后来在ui-select2的介绍中看到这句话:
This directive is now obsolete. A new initiative, more active, and 100% angular is available at https://github.com/angular-ui/ui-select.
发现ui-select2已经有3年没有更新了,果断弃坑选用ui-select。

最后谈谈原则3,还是说ui-select吧,它虽然是ui-select2的改进版,但是性能上是存在问题的,根据stackoverflow上的问答,一个ui-select里包含过多选择项或者一个页面包含过多ui-select控件时,性能有明显降低。因为这一点,曾考虑用其他控件替换掉ui-select,不过项目中并不存在大数据量和过多控件的情况,最后仍然保留了它。在满足原则1和2和前提下,只能尽量满足原则3。

一个新项目在开发前,最好能根据需求调研可能用到的UI控件,并尝试写一些demo,尤其对复杂的UI控件。比如ui-grid,有太多的指令和api,花费在阅读文档和官方实例代码的时间也是一笔不小的投入。

二.自定义指令

自定义的指令要加命名空间(前缀),防止全局指令名污染,就像javascript中防止全局变量污染一样。在项目中,某个页面出现了这样的错误:
Error: [$compile:multidir] Multiple directives [refresh, uiSelectChoices] asking for template on: <ui-select-choices repeat="searchRes in searchRes" refresh="searchMedia($select)">

但是新建一个测试用的解决方案,ui-select却是正常的。几经搜索,后来才发现在项目公共的directive里定义了一个叫refresh的指令,它和ui-select的refresh指令重名了。
解决办法很简单,重命名自定义的refresh指令。

三.页面防抖动

在页面初始化的时候,用户可能会先看到 {{ }},然后闪烁一下才出现真正的内容。这是因为Angularjs会在dom加载完后才会解析{{ }}中的内容,在这之前,{{ }}不是Angularjs的插值表达式,而是文本。
解决办法:
1. 在要显示的内容上使用 ng-cloak指令,并且添加如下样式

  1. <style>
  2. [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak
  3. {
  4. display: none !important;
  5. }
  6. </style>

2. 使用 ng-bind 替代 {{ }}

四.模块化思维

Angularjs推荐模块化开发,module的本意即是模块化,但是在Angularjs 1.X中,module更多体现出来的是一个“命名空间”的概念,而不是真正意义上的模块化。比如A模块依赖B模块,B模块应该是一个独立的东西,但是被A引用之后,A、B模块中的指令,服务,控制器全部混在了一起,使用指令、控制器时甚至不需要指定是哪个模块中的指令和控制器。在Angularjs2中已经抛弃了module,ES6也引入了javascript底层的模块化。在模块化这方面,不必按照Angularjs 1.X铺好的路走。

在项目中,我们的做法是,整个单页面应用是一个module,每个页面对应一个controller和view,公共的功能写在service中(这点还需要改进,呵呵)。
    controller的定位应该是一个完整且尽可能小的功能模块。比如一个列表页,点击某条记录后弹窗显示该记录的详细信息,那么列表页写一个controller,详细页写另一个controller。controller之间是低耦合的,如果有一定的依赖关系,使用事件广播与接收进行通讯($emit, $broadcast, $on)。controller是不可复用的。
    公共的逻辑写在service中,并且按功能分类,满足单一职责。使用时用依赖注入。避免写成全局的公共方法。

五.懒加载

单页面应用如果体量较小,完全不需要懒加载,把所有脚本打包压缩在一起是更好的解决方案。但是体量较大,加载的脚本又多又大,就需要考虑懒加载的方式了。按需加载文件,而不是一次性加载整个应用所需要的全部文件。懒加载的方式推荐用ocLazyLoad,而不要用requireJs。因为requireJs只能加载文件,无法注册module,controller,directive,而ocLazyLoad不但可以加载文件,也可以完成注册。配合ui-route的路由管理,实现懒加载非常方便。

六.性能

Angularjs采用脏检测的方式来检查对象的变化,与其他框架相比——比如同为MVVM模式的vue.js或者使用了虚拟dom的React——Angularjs的性能并不出众。但是,开发一个单页面应用或者一个管理系统,性能完全不是瓶颈。造成Angularjs性能降低的关键因素往往是添加了太多的watcher,超过2000(经验数值)个watcher时,会明显降低性能。所以提高性能的基本方法就是尽量减少watcher数量,比如使用ng-repeat时限制数组的长度并使用track by,以及一次性数据绑定{{::x}}

七.安全

AngularJs本身不允许不安全的代码,比如controller中定义一段带有html标签的字符串:
$scope.html="<p>text</p>";
在页面上显示的是原始的字符串,而不是一个段落。这是Angularjs自身的防XSS攻击机制。除此另外,作为开发人员,应该注意不要在模版中动态签入用户输入的数据。当然,如果需要显示html编码后的内容,也是可以的,使用$sanitize或$sce服务即可。$sanitize会按照Angularjs自身设置的白名单来净化html,$sce服务包含有$sce.trustAs,$sce.trustAsHtml,$sce.trustAsUrl,$sce.trustAsResourceUrl,$sce.trustAsJs等方法,用于编码可信任的html标签。

总结:Angularjs作为当前流行的MVVM框架,开发管理类的CRUD系统真的太合适了。Javascript中一切皆对象,而在Angularjs中可以说一切皆数据,以数据驱动的方式解决dom的更新,提升不少开发效率。本次项目只是Angularjs的首次应用,只接触到了框架本身的部分功能,希望以后能有更多项目应用Angularjs。另外,Angularjs2已经在9月15日正式发布了,也许某天可以用Angularjs2来开发新的项目~

AngularJs项目实践总结的更多相关文章

  1. AngularJs项目

    AngularJs项目实践总结 今年3月接触AngularJs,并且在6月的项目中开始应用,从踩坑到填坑花了不少时间,根据项目中的实际应用情况总结了一些经验,如下: 一.UI控件选择 Angularj ...

  2. 使用Yeoman快速启动AngularJS项目开发

    本博客停止更新,请访问新个人博客:owenchen.net 前言 博客迁移到了BAE上,http://owenchen.net/,以后的文章会首发在自己的博客上,随后在博客园发布. 很久没有写文章了, ...

  3. AngularJS进阶(三十六)AngularJS项目开发技巧之利用Service&Promise&Resolve解决图片预加载问题(后记)

    AngularJS项目开发技巧之利用Service&Promise&Resolve解决图片预加载问题(后记) 前言 在"AngularJS项目开发技巧之图片预加载" ...

  4. 【微信小程序项目实践总结】30分钟从陌生到熟悉 web app 、native app、hybrid app比较 30分钟ES6从陌生到熟悉 【原创】浅谈内存泄露 HTML5 五子棋 - JS/Canvas 游戏 meta 详解,html5 meta 标签日常设置 C#中回滚TransactionScope的使用方法和原理

    [微信小程序项目实践总结]30分钟从陌生到熟悉 前言 我们之前对小程序做了基本学习: 1. 微信小程序开发07-列表页面怎么做 2. 微信小程序开发06-一个业务页面的完成 3. 微信小程序开发05- ...

  5. Hangfire项目实践分享

    Hangfire项目实践分享 目录 Hangfire项目实践分享 目录 什么是Hangfire Hangfire基础 基于队列的任务处理(Fire-and-forget jobs) 延迟任务执行(De ...

  6. Windows on Device 项目实践 3 - 火焰报警器制作

    在前两篇<Windows on Device 项目实践 1 - PWM调光灯制作>和<Windows on Device 项目实践 2 - 感光灯制作>中,我们学习了如何利用I ...

  7. Windows on Device 项目实践 2 - 感光灯制作

    在上一篇<Windows on Device 项目实践 1 - PWM调光灯制作>中,我们学习了如何利用Intel Galileo开发板和Windows on Device来设计并完成一个 ...

  8. Windows on Device 项目实践 1 - PWM调光灯制作

    在前一篇文章<Wintel物联网平台-Windows IoT新手入门指南>中,我们讲解了Windows on Device硬件准备和软件开发环境的搭建,以及Hello Blinky项目的演 ...

  9. Hangfire项目实践

    Hangfire项目实践分享 Hangfire项目实践分享 目录 Hangfire项目实践分享 目录 什么是Hangfire Hangfire基础 基于队列的任务处理(Fire-and-forget ...

随机推荐

  1. windows apache开启url rewrite

    加载Rewrite模块: 在conf目录下httpd.conf中找到 LoadModule rewrite_module modules/mod_rewrite.so 这句,去掉前边的注释符号“#”, ...

  2. Android 升级SQLite数据库

    每一个数据库版本都会对应一个版本号,当指定的数据库版本号大于当前数据库的版本号时,就会进入到onUpGrade()方法中去执行更新操作.需要为每一个版本号赋予其各自改变的内容然后再onUpgrade( ...

  3. ORACLE迁移votedisk,spfile以及OCRfile的方法

    在安装GUI时,创建了第一块ASM磁盘,命名为DATA1,上面存放了spfile文件,ocrfile文件,并且作为了vote盘.感觉名字和实际不符,容易搞混,所以想删除这个磁盘,直接删除会报错: OR ...

  4. 解决首次访问jenkins,输入默认密码之后,一直卡住问题

    简介   安装系统:centos6.5 安装方式:在官网中下载jenkins.war,放到tomcat根目录下的webapps中,启动tomcat(还有一种yum在线安装的方式) 1.首次访问,出现如 ...

  5. pc端页面在移动端显示问题

    1.pc端页面在移动端显示,默认视口宽度是980px(也就是body宽度是980px),可通过meta标签设置为需要的尺寸,比如页面中元素最大宽度是1220px,则如下所示 <meta name ...

  6. TortoiseGit编辑全局变量支持https

    在windows,右键,进入tortoisegit的设置窗口,在左边树形菜单选Git,然后店"编辑全局.gid/config"按钮 输入以下文字 [http] sslVerify ...

  7. 【转】mysql查询结果输出到文件

    转自:http://www.cnblogs.com/emanlee/p/4233602.html mysql查询结果导出/输出/写入到文件 方法一: 直接执行命令: mysql> select ...

  8. 05-String动手动脑问题及课后实验性问题总结

    一.请运行以下实例代码StringPool.java,查看其输出结果.如何解释这样的输出结果?从中你能总结出什么? (1)在Java中,内容相同的字符常量("Hello")只保存一 ...

  9. setWinldowRgn

    CRgn(HRGN) SetWindowRgn setRgn{ CRgn rgnRect; CRgn rgnHole; //获取窗口大小 CRect rcWnd; GetWindowRect(& ...

  10. 增强:MB1A物料价格检查

    INCLUDE:MM07MFP0_PICKUP_AUSFUEHREN FORM:pickup_ausfuehren这是MB1A的PAI的逻辑流里的字段检查 在FORM开始的地方: '. DATA:S_ ...