web 解决方案的 7 个问题
前端开发中的解决方案主要用于解决以下 7 个方面的问题:DOM、Communication(通信)、Utililty(工具包)、Templating(模板)、Component(组件)、Routing(路由)、Architecture(架构)。
DOM
关于DOM,主要包括选择器、DOM 操作、Event(事件)、动画四个部分。DOM相关的解决方案,主要提供以下操作:
- 提供便利的 DOM 查询、操作、移动等操作
- 提供事件绑定及事件代理支持
- 提供浏览器特性检测及 UserAgent 侦测
- 提供节点属性、样式、类名的操作
- 保证目标平台的跨浏览器支持
[ 通用的 DOM 解决方案 ] jQuery、zepto、mootoos等,相比较而言,最稳妥的 DOM 解决方案是 jQuery。
jQuery是曾经风靡一时的最流行的前端解决方案,jQuery特有的链式调用的方式简化了JS的复杂操作,而且使人们不再需要关心兼容性,并提供了大量的实用方法。
zepto是jQuery的精简版,针对移动端去除了大量jQuery的兼容代码,提供了简单的手势,部分API的实现方式不同。
mootools源码清晰易懂,严格遵循Command-Query(命令-查询)的接口规范,没有诸如jQuery的两义性接口。还有一个不得不提的特点是,使用选择器获取的是DOM原生对象,而不是被包装过的对象,而它支持的诸多方法则是通过直接扩展DOM原生对象实现的,这也是它的争议所在。
[ 专业领域的解决方案 ]
上面的解决方案用于解决 DOM 一般的通用问题。随着技术的发展,DOM 的专业领域出现一些小而精致的解决方案。
- 手势:Hammer.JS 包括了常见手势封装(Tab、Hold、Transform、Swifp),并支持自定义扩展。
- 局部滚动:iscroll.JS 是移动端 position:fix + overflow:scroll 的救星。
- 高级动画:Velocity.JS 可以复杂动画序列实现,不仅局限于 DOM。
- 视频播放:Video.JS 类似原生 video 标签的使用方式,对低级浏览器使用 flash 播放器。
Communication(通信)
关于通信,主要包括XMLHttpRequest、Form、JSONP、Socket等。通信相关的解决方案主要提供以下操作:
- 处理与服务器的请求与相应
- 预处理请求数据与响应数据 Error/Success 的判断封装
- 多类型请求,统一接口(XMLHttpRequest1/2、JSONP、iFrame)
- 处理浏览器兼容性
[ 常用的通信解决方案 ] 除了 jQuery 外,其他常用的通信解决方案有 Reqwest、qwest 等
- Reqwest 支持 JSONP,稳定性高,IE6+支持,CORS 跨域,Promise/A 支持。
- qwest代码少、支持XMLHttpRequest2、CORS 跨域、支持高级数据类型(ArrayBuffer、Blob、FormData)。
[ 专业领域的解决方案 ] 对于实时性要求较高的需求可使用socket.io,它实时性高,支持二进制数据流,智能自动回退支持,且支持多种后端语言。
Utililty(工具包)
工具包的主要职责包括以下:
- 提供 JavaScript 原生不提供的功能
- 包装原生方法,使其便于使用
- 异步队列及流程控制
[ 常用的工具包解决方案 ] es5-shim、es6-shim、underscore、Lodash等
shim,翻译过来是垫片的意思。对于es5、es6等标准包括的一些新方法,由于浏览器兼容性不高,所以无法直接使用它们。这时,就需要在保证实现与规范一致的基础上,来扩展原型方法,这种做法就叫做shim。好处在于,实际上就是在使用javascript的语法,但不用去考虑低版本浏览器的兼容性问题。
- es5-shim 提供 ES3 环境下的 ES5 支持
- es6-shim 提供 ES5 环境下的 ES6支持
- underscore 提供兼容 IE6+ 的扩展功能函数
- Lodash是underscore 的高性能版本,方法多为 runtime 编译出来的
Templating(模板)
主要包括:基于字符串的模板(String-based)、基于DOM的模板(DOM-based)、活动模板(Living Template)。
- 基于字符串的模板(String-based),解决方案包括(dustjs、hogan.js、dot.js)。

原理如下:输入一段模板字符串,通过编译之后 ,生成一段Function,通过Function的render或类render函数渲染输入的数据data,输出模板字符串,字符串通过innerHTML或类似的方式渲染成最后的DOM结构。这类模板的问题在于通过字符串生成DOM之后就不再变化,如果在改变输入的数据data,需要重新render,重新生成一个全新的DOM结构,性能较差。但该模板可以在服务器端运行。

- 基于DOM的模板(DOM-based),解决方案包括(angularjs、vuejs、knockout)。

原理如下:将输入的字符串模板通过innerHTML转换为一个无状态DOM树,然后遍历该节点树,去抓取关键属性或语句,来进行相关的绑定,进而变成了有状态的DOM树,最终导致DOM树会与数据模型model进行绑定。这类模板的特点是修改数据时,会使有状态的DOM树实时更新,运行时性能更好,也会保留 DOM 中的已有事件。

- 活动模板(Living Template),解决方案包括(RegularJS、RactiveJS、htmlbar)

原理如下:活动模板融合了字符串模板和DOM模板的技术,模板字符串string通过自定义的解析器DSL-based Parse解析成AST(抽象语法树),通过遍历AST,使用createElement()、setAttribute()等原生DOM方法,生成DOM树,最终导致DOM树会与数据模型model进行绑定。由于其内部完全不使用innerHTML,所以安全性较高。

Component(组件)
组件的主要职责包括以下:
- 提供基础的 CSS 支持
- 提供常见的组件,如 slider、Modal 等
- 提供声明式的调用方式(类似 Bootstrap)
[ 常用组件解决方案 ] 例如:Bootstrap、Foundation等,两者具有移动端first的流式栅格系统,由 sass 组织,可定制 UI。
- Bootstrap 封装了常用的组件,是目前最火的组件解决方案
- Foundation 在国内知名度不高
Routing(路由)
路由在单页系统中非常重要,主要职责如下
- 监听 URL 变化,并通知注册的模块
- 通过 JavaScript 进行主动跳转
- 历史管理
- 对目标浏览器的兼容性支持
无论什么框架,在完成配置之后,内部都有如下图所示的类似的路由表。

[ 常用的路由解决方案 ] page.JS、Director.JS、Stateman、crossroad.JS 等
- page.JS 类似 Express.Router 的路由规则的前端路由库。
- Director.JS 可以前后端使用同一套规则定义路由。
- Stateman 处理深层复杂路由的独立路优库。
- crossroad.JS 老牌路由库,API 功能较为繁琐。
Architecture(架构)
所有的架构都是一个目的,就是解耦。解耦有很多方式,可以通过事件、分层等。市面上,有很多架构模式,包括 MVC、MVVM、MV* 等。架构的职责主要包括以下:
- 提供一种范式帮助(强制)开发者进行模块解耦
- 视图与模型分离
- 容易进行单元测试
- 容易实现应用扩展
以MVVM为例,如下图所示。它包括Model(数据层或模型层)、View(视图层)、ViewModel(控制层)。
- Model,表示数据实体,它们用于记录应用程序的数据。
- View,用于展示界面,界面是数据定制的反映,它包含样式结构定义以及VM享有的声明式数据以及数据绑定。
- ViewModel,是 View 与 Model 的粘合,它通过绑定事件与 View 交互并可以调用 Service 处理数据持久化,也可以通过数据绑定将 Model 的变动反映到 View 中。

它们的关系是:各部分间的通信,都是双向的;View 与 Model 不发生联系,都通过 ViewModel 传递;View 非常薄,不部署任何业务逻辑,称为"被动视图"(Passive View),即没有任何主动性,而 ViewModel 非常厚,所有逻辑都部署在那里。