angular学习笔记(汇智网)一

1.1、Why Angular2

Angular1.x显然非常成功,那么,为什么要剧烈地转向Angular2?


性能的限制

AngularJS当初是提供给设计人员用来快速构建HTML表单的一个内部工具。随着时间的推移,各种特性被加入进去以适应不同场景下的应用开发。然而由于最初的架构限制(比如绑定和模板机制),性能的提升已经非常困难了。

快速变化的WEB

在语言方面,ECMAScript6的标准已经完成,这意味着浏览器将很快支持例如模块、类、lambda表达式、 generator等新的特性,而这些特性将显著地改变JavaScript的开发体验。

在开发模式方面,Web组件也将很快实现。然而现有的框架,包括Angular1.x对WEB组件的支持都不够好。

移动化

想想5年前......现在的计算模式已经发生了显著地变化,到处都是手机和平板。Angular1.x没有针对移动 应用特别优化,并且缺少一些关键的特性,比如:缓存预编译的视图、触控支持等。

简单易用

说实话,Angular1.x太复杂了,学习曲线太陡峭了,这让人望而生畏。Angular团队希望在Angular2中将复杂性封装地更好一些,让暴露出来的概念和开发接口更简单。

 

1.2、ES6工具链

要让Angular2应用跑起来不是件轻松的事,因为它用了太多还不被当前主流浏览器支持 的技术。所以,我们需要一个工具链:

Angular2是面向未来的科技,要求浏览器支持ES6+,我们现在要尝试的话,需要加一些 垫片来抹平当前浏览器与ES6的差异:

  • systemjs - 通用模块加载器,支持AMD、CommonJS、ES6等各种格式的JS模块加载
  • es6-module-loader - ES6模块加载器,systemjs会自动加载这个模块
  • traceur - ES6转码器,将ES6代码转换为当前浏览器支持的ES5代码。systemjs会自动加载 这个模块。
<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <title>hello,angular2</title>
    <style type="text/css">
        body{background:black;color:white;}
        pre{line-height:30px;font-size:20px;}
    </style>
    <!--模块加载器-->
    <script type="text/javascript" src="js/system@0.16.11.js"></script>
    <!--Angular2模块库-->
    <script type="text/javascript" src="js/angular2.dev.js"></script>
    <script>
        //设置模块加载规则
        System.baseURL = document.baseURI;
        System.config({
            map:{traceur:"../js/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>

 源码:https://github.com/(汇智网的英文hubwiz)/angular2-lesson-lib

由于systemjs的动态加载机制,需要使用一个简单的Web服务器来访问*index.html*。

使用node.js命令端,先配置angularJS的开发环境(可以查看文章:angular环境搭建(入门)):

在项目所在的根目录下分别执行以下命令:

npm init -y
npm i angular2@2.0.0-beta.17 --save --save-exact
npm i live-server --save-dev

配置好之后,我们需要在改变文件的同时能自动同步到浏览器,我们还需要在这个文件里面加上以下代码:

"scripts": {    "start": "live-server"
  }

然后执行:

npm start就可以成功创建一个文件服务器,并且成功运行项目。

 

 

1.3、初识Angular2

写一个Angular2的Hello World应用相当简单,分三步走:

1. 引入Angular2预定义类型

import {Component,View,bootstrap} from "angular2/angular2";

import是ES6的关键字,用来从模块中引入类型定义。在这里,我们从angular2模块库中引入了三个类型: Component类、View类和bootstrap函数。

2. 实现一个Angular2组件

实现一个Angular2组件也很简单,定义一个类,然后给这个类添加注解:

1 @Component({selector:"ez-app"})
2 @View({template:"<h1>Hello,Angular2</h1>"})
3 class EzApp{}

class也是ES6的关键字,用来定义一个类。@Component和@View都是给类EzApp附加的元信息, 被称为注解/Annotation。

@Component最重要的作用是通过selector属性(值为CSS选择符),指定这个组件渲染到哪个DOM对象上。 @View最重要的作用是通过template属性,指定渲染的模板。

3. 渲染组件到DOM

将组件渲染到DOM上,需要使用自举/bootstrap函数:

bootstrap(EzApp);

这个函数的作用就是通知Angular2框架将EzApp组件渲染到DOM树上。

简单吗?我知道你一定还有疑问,别着急,我们慢慢把缺失的知识点补上!

 

1.4、注解/Annotation

你一定好奇@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}
});

 

1.5、小结

如果你了解一点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了。

文件说明:

# angular2-lesson-lib

这是汇智网课程[Angular2入门]使用的
库文件,你可以下载到本地练习。

文件清单:

* index.html - 测试文件
* lib/angular2.dev.js - angular2基础框架
* lib/render.dev.js - angular2渲染库
* lib/router.dev.js - angular2路由库
* lib/system@0.16.11.js - systemjs加载库
* lib/system@0.16.11.js.map - systemjs加载库MAP文件
* lib/system.config.js - systemjs配置文件
* lib/es6-module-loader@0.16.6.js - es6模块加载库,systemjs调用它载入es6模块
* lib/es6-module-loader@0.16.6.js - es6模块加载库MAP文件
* lib/traceur.js - es6转码库

## 使用方法

由于systemjs的动态加载机制,需要使用一个简单的Web服务器来访问*index.html*。例如使用Python:

    ~$ git clone https://github.com/(汇智网的英文)/angular2-lesson-lib.git
    ~$ cd angular2-lesson-lib
    ~/angular2-lesson-lib$ python -m SimpleHTTPServer

现在可以使用浏览器访问*http://localhost:8000/*来测试了。    

 

 

2.1、最简单的模板

组件的View注解用来声明组件的外观,它最重要的属性就是template - 模板。 Angular2的模板是兼容HTML语法的,这意味着你可以使用任何标准的HTML标签编写 组件模板。

所以,在最简单的情况下,一个Angular2组件的模板由标准的HTML元素构成,看起来就是 一段HTML码流。Angular2将原封不同地渲染这段模板:

有两种方法为组件指定渲染模板:

1. 内联模板

可以使用组件的View注解中的template属性直接指定内联模板:

@View({
    template : `<h1>hello</h1>
                <div>...</div>`
})

在ES6中,使用一对`符号就可以定义多行字符串,这使得编写内联的模板轻松多了。

2. 外部模板

也可以将模板写入一个单独的文件:

<!--ezcomp-tpl.html-->
<h1>hello</h1>
<div>...</div>

然后在定义组件时,使用templateUrl引用外部模板:

@View({
    templateUrl : "ezcomp-tpl.html"
})

 

 2.2、directives - 使用组件

在Angular2中,一个组件的模板内除了可以使用标准的HTML元素,也可以使用自定义的组件!

这是相当重要的特性,意味着Angular2将无偏差地对待标准的HTML元素和你自己定义的组件。这样, 你可以建立自己的领域建模语言了,这使得渲染模板和视图模型的对齐更加容易,也使得模板的语义性 更强:

 

声明要在模板中使用的组件

不过,在使用自定义组件之前,必需在组件的ViewAnnotation中通过directives属性声明这个组件:

@View({
    directives : [EzComp],
    template : "<ez-comp></ez-comp>"
})

你应该注意到了,directives属性的值是一个数组,这意味着,你需要在这里声明所有你需要在模板 中使用的自定义组件。

 

2.3、{{model}} - 文本插值

 在模板中使用可以{{表达式}}的方式绑定组件模型中的表达式,当表达式变化时, Angular2将自动更新对应的DOM对象:

上图的示例中,模板声明了h1的内容将绑定到组件实例的title变量。Angular2 框架将实时检测title的变化,并在其变化时自动更新DOM树中h1的内容。

2.4、[property] - 绑定属性

在模板中,也可以使用一对中括号将HTML元素或组件的属性绑定到组件模型的某个表达式, 当表达式的值变化时,对应的DOM对象将自动得到更新:

等价的,你也可以使用bind-前缀进行属性绑定:

@View({template:`<h1 bind-text-content="title"></h1>`})

很容易理解,通过属性,应用相关的数据流入组件,并影响组件的外观与行为。

需要注意的是,属性的值总是被当做调用者模型中的表达式进行绑定,当表达式变化时,被 调用的组件自动得到更新。如果希望将属性绑定到一个常量字符串,别忘了给字符串加引号,或者, 去掉中括号:

1 //错误,Angular2将找不到表达式 Hello,Angular2
2 @View({template:`<h1 [text-content]="Hello,Angular2"></h1>`})
3 //正确,Angular2识别出常量字符串表达式 'Hello,Angular2'
4 @View({template:`<h1 [text-content]="'Hello,Angular2'"></h1>`})
5 //正确,Angular2识别出常量字符串作为属性textContent的值
6 @View({template:`<h1 text-content="Hello,Angular2"></h1>`})

练习:

修改示例代码,使EzApp组件的标题颜色每秒钟随机变化一次!(还没实现)

 

1.5、(event) - 监听事件

 在模板中为元素添加事件监听很简单,使用一对小括号包裹事件名称,并绑定 到表达式即可:

上面的代码实例为DOM对象h1的click事件添加监听函数onClick()。

另一种等效的书写方法是在事件名称前加on-前缀:

@View({template : `<h1 on-click="onClick()">HELLO</h1>`})

 

1.6、#var - 局部变量

有时模板中的不同元素间可能需要互相调用,Angular2提供一种简单的语法将元素 映射为局部变量:添加一个以#或var-开始的属性,后续的部分表示变量名, 这个变量对应元素的实例。

在下面的代码示例中,我们为元素h1定义了一个局部变量v_h1,这个变量指向 该元素对应的DOM对象,你可以在模板中的其他地方调用其方法和属性:

@View({
    template : `
        <h1 #v_h1>hello</h1>
        <button (click) = "#v_h1.textContent = 'HELLO'">test</button>
    `
})

如果在一个组件元素上定义局部变量,那么其对应的对象为组件的实例:

@View({
    directives:[EzCalc],
    template : "<ez-calc #c></ez-calc>"
})

在上面的示例中,模板内的局部变量c指向EzCalc的实例。

 

posted @ 2016-09-05 16:07  chenxj  阅读(171)  评论(0)    收藏  举报