Angular1.x显然非常成功,那么,为什么要剧烈地转向Angular2?
性能的限制AngularJS当初是提供给设计人员用来快速构建HTML表单的一个内部工具。随着时间的推移,各种特性被加入进去以适应不同场景下的应用开发。然而由于最初的架构限制(比如绑定和模板机制),性能的提升已经非常困难了。
快速变化的WEB
在语言方面,ECMAScript6的标准已经完成,这意味着浏览器将很快支持例如模块、类、lambda表达式、generator等新的特性,而这些特性将显著地改变JavaScript的开发体验。
在开发模式方面,Web组件也将很快实现。然而现有的框架,包括Angular1.x对WEB组件的支持都不够好。
移动化
想想5年前......现在的计算模式已经发生了显著地变化,到处都是手机和平板。Angular1.x没有针对移动应用特别优化,并且缺少一些关键的特性,比如:缓存预编译的视图、触控支持等。
简单易用
说实话,Angular1.x太复杂了,学习曲线太陡峭了,这让人望而生畏。Angular团队希望在Angular2中将复杂性封装地更好一些,让暴露出来的概念和开发接口更简单。
<!doctype html> <html> <head> <meta charset="utf-8"> <title>why angular2</title> </head> <body> <h1>Why Angular2?</h1> </body> </html>
要让Angular2应用跑起来不是件轻松的事,因为它用了太多还不被当前主流浏览器支持的技术。所以,我们需要一个工具链:
Angular2是面向未来的科技,要求浏览器支持ES6+,我们现在要尝试的话,需要加一些垫片来抹平当前浏览器与ES6的差异:
<!doctype html> <html> <head> <meta charset="utf-8"> <title>hello,angular2</title> <!--模块加载器--> <script type="text/javascript" src="lib/[email protected]"></script> <!--Angular2模块库--> <script type="text/javascript" src="lib/angular2.dev.js"></script> <script> //设置模块加载规则 System.baseURL = document.baseURI; System.config({ map:{traceur:"lib/traceur"}, traceurOptions: {annotations: true} }); </script> </head> <body> <img src="img/jay.gif"> <pre class="logger"></pre> <!--定义一个ES6脚本元素--> <script type="module"> //用ES6语法定义一个类 export class Logger{ constructor(){ this.el = document.querySelector("pre.logger"); this.lines = []; } log(str){ this.lines.push(str); this.el.textContent = this.lines.join("\n"); } } //实例化,测试一下 var _ = new Logger(); _.log("哎呦,不错哦!"); _.log("真的是用ES6写的噢!"); </script> </body> </html>
body{background:black;color:white;} pre{line-height:30px;font-size:20px;}
写一个Angular2的Hello World应用相当简单,分三步走:
1. 引入Angular2预定义类型
- import {Component,View,bootstrap} from "angular2/angular2";
import是ES6的关键字,用来从模块中引入类型定义。在这里,我们从angular2模块库中引入了三个类型:Component类、View类和bootstrap函数。
2. 实现一个Angular2组件
实现一个Angular2组件也很简单,定义一个类,然后给这个类添加注解:
- @Component({selector:"ez-app"})
- @View({template:"<h1>Hello,Angular2</h1>"})
- class EzApp{}
class也是ES6的关键字,用来定义一个类。@Component和@View都是给类EzApp附加的元信息,被称为注解/Annotation。
@Component最重要的作用是通过selector属性(值为CSS选择符),指定这个组件渲染到哪个DOM对象上。@View最重要的作用是通过template属性,指定渲染的模板。
3. 渲染组件到DOM
将组件渲染到DOM上,需要使用自举/bootstrap函数:
- bootstrap(EzApp);
这个函数的作用就是通知Angular2框架将EzApp组件渲染到DOM树上。
简单吗?我知道你一定还有疑问,别着急,我们慢慢把缺失的知识点补上!
<!doctype html> <html> <head> <meta charset="utf-8"> <title>hello,angular2</title> <!--模块加载器--> <script type="text/javascript" src="lib/[email protected]"></script> <!--Angular2模块库--> <script type="text/javascript" src="lib/angular2.dev.js"></script> <script> //设置模块加载规则 System.baseURL = document.baseURI; System.config({ map:{traceur:"lib/traceur"}, traceurOptions: {annotations: true} }); </script> </head> <body> <!--组件渲染锚点--> <my-app></my-app> <!--定义一个ES6脚本元素--> <script type="module"> //从模块库引入三个类型定义 import {Component,View,bootstrap} from "angular2/angular2"; //组件定义 @Component({selector:"my-app"}) @View({template:"<h1>Hello,Angular2</h1>"}) class EzApp{} //渲染组件 bootstrap(EzApp); </script> </body> </html>
h1{background:black;color:white;display:inline-block}
你一定好奇@Component和@View到底是怎么回事。看起来像其他语言(比如python)的装饰器,是这样吗?
ES6规范里没有装饰器。这其实利用了traceur的一个实验特性:注解。给一个类加注解,等同于设置这个类的annotations属性:
- //注解写法
- @Component({selector:"ez-app"})
- class EzApp{...}
等同于:
- class EzApp{...}
- EzApp.annotations = [new Component({selector:"ez-app"})];
很显然,注解可以看做编译器(traceur)层面的语法糖,但和python的装饰器不同,注解在编译时仅仅被放在annotation里,编译器并不进行解释展开 - 这个解释的工作是Angular2完成的:
据称,注解的功能就是Angular2团队向traceur团队提出的,这不是traceur的默认选项,因此你看到,我们配置systemjs在使用traceur模块时打开注解:
- System.config({
- map:{traceur:"lib/traceur"},
- traceurOptions: {annotations: true}
- });
</script> <!--Angular2模块库--> <script type="text/javascript" src="lib/angular2.dev.js"></script> <script> //设置模块加载规则 System.baseURL = document.baseURI; System.config({ map:{traceur:"lib/traceur"}, traceurOptions: {annotations: true} }); </script> </head> <body> <!--组件渲染锚点--> <my-app></my-app> <!--定义一个ES6脚本元素--> <script type="module"> //从模块库引入三个类型定义 import {Component,View,bootstrap} from "angular2/angular2"; //组件定义 @Component({selector:"my-app"}) @View({template:"<h1>Hello,Annotation</h1>"}) class EzApp{} //渲染组件 bootstrap(EzApp); </script> </body> </html>
h1{background:black;color:white;display:inline-block}
如果你了解一点Angular1.x的bootstrap,可能隐约会感受到Angular2中bootstrap的一些变化 - 我指的并非代码形式上的变化。
以组件为核心
在Angular1.x中,bootstrap是围绕DOM元素展开的,无论你使用ng-app还是手动执行bootstrap()函数,自举过程是建立在DOM之上的。
而在Angular2中,bootstrap是围绕组件开始的,你定义一个组件,然后启动它。如果没有一个组件,你甚至都没有办法使用Angular2!
支持多种渲染引擎
以组件而非DOM为核心,意味着Angular2在内核隔离了对DOM的依赖 - DOM仅仅作为一种可选的渲染引擎存在:
上面的图中,DOM Render已经实现,Server Render正在测试,iOS Render和Android Render是可预料的特性,虽然我们看不到时间表。
这有点像React了。
<!doctype html> <html> <head> <meta charset="utf-8"> <title>hello,angular2</title> <!--模块加载器--> <script type="text/javascript" src="lib/[email protected]"></script> <!--Angular2模块库--> <script type="text/javascript" src="lib/angular2.dev.js"></script> <script> //设置模块加载规则 System.baseURL = document.baseURI; System.config({ map:{traceur:"lib/traceur"}, traceurOptions: {annotations: true} }); </script> </head> <body> <!--组件渲染锚点--> <my-app></my-app> <!--定义一个ES6脚本元素--> <script type="module"> //从模块库引入三个类型定义 import {Component,View,bootstrap} from "angular2/angular2"; //组件定义 @Component({selector:"my-app"}) @View({template:"<h1>Angular2 - 以组件为基石</h1>"}) class EzApp{} //渲染组件 bootstrap(EzApp); </script> </body> </html>
h1{background:black;color:white;display:inline-block}