引言
传统的jQuery的前端项目虽然大大的简化了DOM操作,但仍然存在如下问题:
1. 代码结构耦合性太高,模块化程度低;
2. 缺乏依赖注入机制;
3. 频繁的DOM操作,代码过于臃肿。
前端MVC框架的出现则很好的解决了jQuery项目带来的问题。当前前端MVC框架越来越火热,越来越多的公司开始放弃传统的jQuery,而转向MVC框架,如AngularJS,backbone等。在众多前端MVC框架中,谷歌出身的AngularJS算是佼佼者。
乐视云前端团队在2015年开始使用AngularJS来构建新项目。迄今为止已经成功的将云主机移植到了AngularJS版本上。下面讲述构建基于AngularJS的项目时遇到的问题和经验。
一云主机前端架构简介
根据angular提供的控制器,过滤器,视图,等概念我们将前端结构划分如下。
Router用来实现页面的路由功能,是页面的分发入口。AngularJS可以使用Router替换页面中的局部显示。将公共的菜单,导航条与具体页面分离出来达到页面部分的复用。
Coludvm是云主机相关的具体代码。根据AngularJS的MVC结构,分为控制器和视图模板两部分,控制器是AngularJS程序的核心部分,所有的业务逻辑都应该放在这里,控制器绑定的数据则以模板的形式放在前端页面中,view和Template都是存放视图模板的地方,区别是view里存的是页面模板,Template里存放的是对话框模板。
Common是项目的公共模块,模块里三部分,filter,service,directive都是AngularJS提供的用于模块化开发的三个功能,filter是数据过滤器,可用于基本的数据显示格式化,直接在模板中使用,service是服务模块,提供了公共功能的封装,如HTTP请求,消息提示框,URL配置获取等。directive是AngularJS的一个特色,它一般封装了对DOM的一些操作,因为好的实践中不能在控制器中直接操作DOM,这些作用在DOM上的指令大大增强了普通DOM的功能,通过对DOM的操作封装了一些项目通用的控件。以上划分只能满足基本的功能开发,实际中经常需要引用第三方的插件,AngularJS满足了我们这方面的需求,AngularJS提供了相当丰富的插件库,使用简单,可以作为AngularJS的一个模块集成到AngularJS项目中。尽管AngularJS使用方便,架构清晰,但使用中还是遇到了各种问题。
二项目遇到的问题和采用的解决方案
1控制器代码膨胀
虽然开始阶段遵循了控制器里不要操作DOM这一铁则,但随着项目进展,代码愈发复杂,控制器也越来越臃肿。AngularJS的依赖机制很好的解决了这个问题,数据的格式化和数据过滤应全部放在filter中,和项目有关的数据映射应该提取出来,减少switch分支映射代码,做到源数据只有一份,衍生数据和格式全部脱离源数据。其中的一些配置数据则可以放在服务里,如在云主机项目中,Config服务模块存放了配置相关的信息,任何想使用它的地方只要引用Config依赖就可以了。总之写代码时要注意区分当前代码性质和归属。
2HTTP状态返回错误问题
后台会返回三种状态:
(1) 表示成功,需要把数据返回给controller;
(2) 表示登录超时,需要刷新页面跳转到登录页面;
(3) 表示后台错误,需要把错误信息提示给用户。
我们想要在全局的地方对这些逻辑进行了统一处理,但因为向后端的请求都是$http实现的,无法对返回的数据进行拦截处理。后来通过在HttpService中对$http用promise进行了一层装饰,在装饰中添加了我们的逻辑,解决了这个问题。
3表单中文输入问题
由于AngularJS自身的BUG,一些指令使用中存在一些需要注意的问题,这些BUG出现的毫无道理,也没有明确的解释原因。只能使用时可以避开和采用一些hack写法。最常见的问题就是ng-if使用问题,很多奇怪的BUG都是源于这个指令使用,我们的经验是如果遇到了奇怪的BUG,首先考虑用ng-show替换ng-if。ng-if这个指令会产生很多问题,甚至影响到其他AngularJS插件。
三前端组件库
除了上述问题解决方案,AngularJS中一个重点部分就是前端组件库。前端组件库能够极大的提高代码的可复用率和开发的效率。AngularJS中使用指令封装一些可复用的功能操作,指令可以被用来创建自定义的HTML标签,这些标签可以用作新的自定义的控件。它们也可以用来"渲染"有一定行为的元素,也可以以一些有趣的方式来操作DOM属性。一个指令就是一个能引入新语法的东西。把分离的组件组合成一个组件,这种创建应用的方式将使得添加、修改和删除页面功能变得异常简单。指令是AngularJS的一个非常强大且独有的特性。前端组件库能够极大的提高代码的可复用率和开发的效率。
AngularJS通过directive能够很好的实现组件开发。我们把项目中多次用到的UI组件封装在了指令中,在使用时,简单添加一个属性就能实现相当复杂的功能。
四前端自动化工具与单元测试1前端自动化工具
接下来的部分介绍我们项目中的前端工具与单元测试。前端自动化工具,主要用来负责上线前脚本的合并,压缩,给脚本添加版本号,以及线上环境和测试环境的配置切换。我们采用了gulp来做我们的自动化工具,主要是考虑到gulp丰富的插件,可以帮助我们基本的功能,例如js压缩我们用的gulp-uglify,给脚本添加版本号用的是gulp-rev,而且基于gulp我们还可以做一些自定义的开发,例如RequireJS模块的压缩我们用的是r.js,在自动化处理的入口处我们使用RequireJS提供的r.js进行第一步的压缩处理, 利用RequireJS的文件依赖关系和自定义的config文件配置进行压缩合并。我们通过gulp可以把RequireJS模块合并集成到框架中,使自动化工具能够满足我们的一些特定需求。
2前端单元测试框架
因为AngularJS本身是通过依赖注入的方式的来实现模块的依赖关系的,因此可以很方便的分模块的编写单元测试的用例。我们的单元测试框架是基于karma和jasmine来实现的。
五开发环境的前后端分离的架构
最后说一下我们开发环境中的前后端分离的架构。为什么要前后端分离,原因有三:
1. 前后端代码耦合在一块不方便单独的部署;
2. 前后的IDE不太一样,后端服务配置实在太过复杂;
3. 前端需要自己的一套自动化工具,单元测试框架。
我们使用了Node.js作为前后端分离的中间代理,对于浏览器发出的静态资源请求和api数据请求作出分发,这样前端代码完全脱离后端服务项目,而后端服务只提供api数据。
六展望
目前云主机项目基于AngularJS解决了传统jQuery项目中存在的模块化开发相关问题。通过指令封装了自己的ui库,做到了高度复用。从jQuery到AngularJS,我们迈出了一大步,未来我们计划开发一些通用的ui接口,不只是在AngularJS框架下使用,通过配置改变和任何项目达到无缝连接。
彩蛋技术干货可定制啦!