项目背景
effevo致力于为用户提供最方便的云端任务管理工具,任务管理过程中主要涉及的就是数据的CRUD,并能够将这种数据变化实时的反馈出来;有些地方(比如甘特图)需要比较复杂的dom操作和交互;有些页面(比如首页)有SEO的要求。由于系统的这种复杂性决定不可能由单一的技术来实现整体的系统。
本文主要对Effevo 前端的整体架构做了一个简单的介绍,给大家提供一种前端架构的解决方案。其中也还存在着一些问题, 欢迎大家与我们交流,共同改进。
前端架构
针对上面的项目背景,我们初步决定 前端采用angularJS + 部分jQuery; 后端采用nodejs搭建整体的项目架构。
一. angularjs
面向前端的MVC框架, 前端开发变得更加规范。实现了数据的双向绑定,把开发人员从复杂的dom操作中解放出来,将关注点放在数据和业务逻辑操作上面;MVC架构使得用angularJS能够很方便的进行模块化开发;angularJS的学习成本比较低,使得开发人员能够迅速的进入开发状态。
二.前端路由
有angularJS自带的ngRoute和基于ngRoute扩展的ui-router两种方案。
1. ngRoute: 靠检测URL改变,绘制视图, 一个app只能有一个视图,URL之间的跳转会造成某些 $scope信息的重复载入,这也意味着没法进行视图之间的嵌套,也不允许在一个页面上有多个view,这样不利于模块化的开发或者说模块化开发的复杂度比较高,因为在实际开发过程中一个页面可以拆分成多个并列的模块和嵌套的模块,这些模块可能不是由一个人开发的,这种情况下如果每个人需要维护的代码量会比较大,在开发的过程中容易出错,整体代码结构不够清晰。
2.ui-router: 靠状态变化绘制视图。ui-router修复了很多ngRoute面临的问题,她有以下两个特性:
- 支持在同一个URL下面的多个视图
- 支持URL的多级嵌套
<body> <div ui-view='nav'></div> <div ui-view='content'> </div> <div ui-view='footer'></div> </body>
这样整体页面拆分成了3个独立的ui-view,导航视图, 内容视图 和 底部的视图。
对于内容视图的模板里面的内容大体是这样的:
<div> <div class='leftNav'></div> <div ui-view></div> </div>
内部构成二级导航,根据二级导航的切换ui-view的内容进行变化,而ui-view里面的内容可以分别由不同的人员开发。这样不管是嵌套还是并列的视图都可以将里面的模块拆分出来,代码结构也更清晰,维护起来也比较方便。
三. 组件化开发
在项目开发过程中,不同的子系统和不同的模块之间涉及到很多共性的东西,我们称之为组件。如果每个子系统和模块分别实现一套的话不仅开发量巨大,而且以后维护起来也是个灾难。而angularJS 中的指令(directive)提供了很方便的模式实现组件化。举个例子:
例如任务管理中任务编辑页面下面的评论框:
在话题列表页下面是这样的:
内部的功能是完全一样的,我在代码里面是这样用的:
<div ee-comment="taskDynamicsInfo.projectCommentCfg"></div>
通过配置决定评论框的行为,这样以后如果问题页面或者文件管理页面需要这种评论框的时候直接拿过来就可以使用了,这样就实现了write once, use everyWhere。对于项目的开发效率来说有非常大的提高。Effevo 中存在这大量的这样的组件:select选择框、左侧导航、日期选择框、TreeList等等;凡是其他地方可能够用到的我们统一都做成组件,甚至以后应用到其他项目中去。
四. 前端样式库
前端开发过程中另一个重要的方面是样式统一问题,Effevo最初的版本里面我们采用的是bootstrap样式库。后来发现bootstrap 样式库里面的样式和UED设计稿的风格差别比较大,因此我们决定自己实现一套CSS 样式库,采用less 实现,将统一的样式提取出来。整体结构如下:
分别存放全局变量、 覆盖浏览器默认样式、全局通用样式和mixIn 样式,如果后面样式库扩展的时候可以将less拆分成不同的小文件。
五. 模块加载器
目前主流的模块加载器有requireJS 和 SeaJS, 与requireJS 相比,seaJS专注于浏览器端的模块加载,遵循CMD规范, 更简洁优雅。但是感觉差别不是特别大,看团队使用习惯,选择一个即可,我们开始使用的是seaJS,后来一直延续下来。目前看来也存在着一些问题,例如打包过程中的路径问题,第三方库的依赖问题等。而requireJS中这些问题都得到很好的解决,并且现在很多第三方的库都默认支持AMD标准了。
六. 前后端交互
Effevo 前端通过采用Restful 形式的API与后台交换json格式的数据的形式达到前后端数据交互的目的。另外系统中存在着对数据实时性要求比较高的功能模块,例如在任务管理模块,用户A和B在不同的地方同时在编辑同一个项目(经过我们调查这种情况经常出现),如果A编辑的数据没有立刻同步到B的客户端的话容易出现数据丢失或者混乱的情况,因为系统只能保存最后一次修改的内容。Effevo最初的版本中没有处理这种情况,所以经常会接到用户反馈修改的数据莫名丢失。为了解决这个问题我们引入了webSocket, 每当有用户登录到系统后,会自动与后台服务器建立一个 webSocket的连接, 这样数据在其他客户端修改之后会立刻广播到其他客户端,同步进行修改,能够解决上面的问题。与传统的轮询方案相比,webSocket 能够主动给客户端发送消息,只需要建立一次链接,并且node的后台能够保证在并发量很大的情况下依然能有很高的处理效率。