在Web前端技术飞速发展的今天,Angular 1.x可以说是一个比较旧的东西,而ES6是新生事物。我们想要把这两个东西结合起来,感觉就好像“十八新娘八十郎,苍苍白发对红妆。”但这件事的难度也并不大,因为我们最终是要把ES6构建成ES5代码,而ES5代码是可以很容易和Angular 1.x协作的。
不过,为什么我们要干这件事呢?
在这篇文章中,我提到过:
尽管在整个前端开发圈中,大家并不是很欢迎Angular,而且很多人认为它的1.x版本已经衰落,但我跟 @小猪有个观点是一致的,那就是:“在企业开发领域,ng1的应用才方兴未艾”,也就是说,它在这个领域其实还是上升阶段。
所以,在不少场合下,它还是要承载一些开发工作,部分老系统的逐步平滑迁移也是比较重要的。
做这件事的另外一个意图是:虽然未来的框架选型会有不少争议,但有一点毋庸置疑,那就是业务JS代码的全面ES6或者TS化,这一点我们现在就可以着手去做,并且可以尽量把数据和业务逻辑层实现成框架无关的形式。
在这篇里大致讲了点对这方面的考虑。
模块机制
Angular 1.x的module机制是比较别扭的,也是一种框架私有的模块机制,所以,我们需要淡化这层东西,具体的措施是:
- 把各功能模块的具体实现代码独立出来
- module机制作为一个壳子,对功能模块进行包装
- 每个功能分组,使用一个总的壳子来包装,减少上级模块的引用成本
- 每个壳子文件把module的name属性export出去
举例来说,我们有一个moduleA,里面有serviceA,serviceB,那么,就有这样一些文件:
serviceA的实现,service/a.js
1 |
export default class ServiceA {} |
serviceB的实现,service/b.js
1 |
export default class ServiceB {} |
moduleA的壳子定义,moduleA.js
1 2 3 4 5 6 7 |
import ServiceA from "./services/a"; import ServiceB from "./services/b"; export default angular.module("moduleA", []) .service("ServiceA", ServiceA) .service("ServiceB", ServiceB) .name; |
存在一个moduleB要使用moduleA:
1 2 3 |
import moduleA from "./moduleA"; export default angular.module("moduleB", [moduleA]).name; |
注意,这里为什么我们要export module的name呢?这是为了这个module的引用者方便,如果某个module改名了,所有依赖它的module可以不修改代码。
在这里我们可以看到,a.js,b.js,moduleA.js这三个文件,只有moduleA是作为一次性的配置项,而a和b可以尽量实现成框架无关的代码,这样将来的迁移代价会比较小。
service,factory,controller,filter
在Angular 1.x里面,有factory和service两个概念,其实这两者可以替换,service传入的是构造函数,通过new创建出实例,而factory传入的是工厂函数,通过对这个工厂函数的调用而创建实例。
所以,如果要使用ES6代码来编写这个部分,也就很自然了:
serviceA的实现,service/a.js
1 |
export default class ServiceA {} |
serviceA的模块包装器moduleA的实现
1 2 3 4 5 |
import ServiceA from "./service/a"; export angular.module("moduleA", []) .service("ServiceA", ServiceA) .name; |
factoryA的实现,factory/a.js
1 2 3 4 5 |
import EntityA from "./model/a"; export default function FactoryA { return new EntityA(); } |
factoryA的模块包装器moduleA的实现
1 2 3 4 5 |
import FactoryA from "./factory/a"; export angular.module("moduleA", []) .factory("FactoryA", FactoryA) .name; |
注意看这个例子中,FactoryA函数的返回结果是new EntityA,在实际项目中,这里不一定是通过某个实体类创建的,也可能是直接一个对象字面量:
in-wrap">
|