注解/Annotation
- @Component 和 @View
给一个类加注解,等同于设置这个类的annotation属性
//注解写法
@Component({selector:"ez-app"})
class EzApp{...}
//以上代码等同于
class EzApp{...}
EzApp.annotations = [new Component({selector:"ez-app"})];
注解在编译时仅仅被放在annotation里,编译器并不进行解释展开,这个解释的工作是 Angular2完成的
图片引用---------->annotation.jpg
- 模版
- 内联模版
@View({
template : `<h1>hello</h1>
<h2>world</h2>`
})
- 外部模版
<!--module.html文件中-->
<h1>hello</h1>
<h2>world</h2>
<!--模版调用-->
@View({
templateUrl : "module.html"
})
- directive使用组件
图片引用-----> component-template.jpg
// class EzApp{EzCard}
@Component({selector:"ez-app"})
@View({
directives:[EzCard],
template:`
<p class="ez-app">
<h1>EzApp</h1>
<ez-card></ez-card>
</p>`
})
class EzApp{}
// class EzCard
@Component({selector : "ez-card"})
@View({
template : `
<p class="ez-card">
<h1>EzCard</h1>
</p>`
})
class EzCard{}
bootstrap(EzApp);
- {{model}}文本插值
//程序实例
@Component({selector : "ez-app"})
@View({
template:`
<p>
<h1>{{title}}</h1>
<p>
<span>{{date}}</span>
<span>{{source}}</span>
</p>
<p>{{content}}</p>
</p>
})
class EzApp{
constructor(){
this.title = "世界,你好!";
this.date = "2016-10-17 10 : 10 : 10";
this.source = "江西-南昌"
this.content = "曾经沧海难为水,除却巫山不是云";
}
}
bootstrap(EzApp);
- [property]绑定属性
引用图片prop-bind.jpg
// 注意事项
//使用前缀 bind-来进行绑定属性
@View({template:`<h1 bind-text-content="title"></h1>`})
// 使用在属性前加[]进行绑定
@View({template:`<h1 [text-content]="title"></h1>`})
//使用中括号[]绑定属性时应注意以下事项
{
//错误,Angular2将找不到表达式 Hello,Angular2
@View({template:`<h1 [text-content]="Hello,Angular2"></h1>`})
//正确,Angular2识别出常量字符串表达式 'Hello,Angular2'
@View({template:`<h1 [text-content]="'Hello,Angular2'"></h1>`})
//正确,Angular2识别出常量字符串作为属性textContent的值
@View({template:`<h1 text-content="Hello,Angular2"></h1>`})
}
- (event)监听事件
图片引用event-bind.jpg
//代码实例 前缀on-进行事件绑定
@View({template : `<h1 on-click="onClick()">HELLO</h1>`})
// 为属性添加 括号()
@View({template : `<h1 (click)="onClick()">HELLO</h1>`})
- #var局部变量
@View({
template :
<h1 #h_title>我是标题</h1>
<button (click)= "h_title.contentText = '我改变了'">改变标题</button>
})
组件开发-模版的逻辑控制
- 使用条件逻辑
有时我们需要模板的一部分内容在满足一定条件时才显示,比如右边示例中的EzReader组件, 对于试用用户,它将在正文之上额外显示一个广告:
引用图片---->ngif.jpg
这是指令NgIf发挥作用的场景,它评估属性ngIf的值是否为真,来决定是否渲染 template元素的内容:
@View({
template:
`
<!--判断trial是否为true-->
<template [ng-ig]="trial==true">
<img src = "abc.jpg"/>
</template>
<!--以下是正文-->
<pre>...
`
})
//Angular2同时提供了两种语法糖,让NgIf写起来更简单,下面的两种书写方法和上面 的正式语法是等效的
//使用template attribute
<img src="ad.jpg" template="ng-if tiral==true">
//使用*前缀
<img src="ad.jpg" *ng-if="tiral==true">
//较好实例说明
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Interpolation</title>
<script type="text/javascript" src="lib/system@0.16.11.js"></script>
<script type="text/javascript" src="lib/angular2.dev.js"></script>
<script type="text/javascript" src="lib/system.config.js"></script>
</head>
<body>
<ez-app></ez-app>
<script type="module">
//引入NgIf类型
import {Component,View,bootstrap,NgIf} from "angular2/angular2";
@Component({selector:"ez-app"})
@View({
directives:[EzReader],
template:`
<ez-reader [trial]="true"></ez-reader>
`
})
class EzApp{}
@Component({
selector : "ez-reader",
properties:["trial"]
})
@View({
directives:[NgIf],
template : `
<img [src]="banner" *ng-if="trial==true">
<pre>{{content}}</pre>`
})
class EzReader{
constructor(){
var self = this;
this._trial = true;
this.banner = "img/banner.jpg";
this.content = `
“没关系,我已经没有放射性了。”史强对坐在旁边的汪森说,“这两天,我让人家像洗面口袋似的翻出来洗了个遍。
这次会议本来没安排你参加,是我坚决要求请你来的,嘿。我保准咱哥俩这次准能出风头的。”
史强说着,从会议桌上的烟灰缸中拣出一只雪茄屁股,点上后抽一口,点点头,心旷神怡地把烟徐徐吐到对面与会
者的面前,其中就有这支雪茄的原主人斯坦顿,一名美国海军陆战队上校,他向大史投去鄙夷的目光。
这次与会的有更多的外国军人,而且都穿上了军装。在人类历史上,全世界的武装力量第一次面对共同的敌人。
常伟思将军说:“同志们,这次与会的所有人,对目前形势都有了基本的了解,用大史的话说,信息对等了。人类
与外星侵略者的战争已经开始,虽然在四个半世纪后,我们的子孙才会真正面对来自异星的三体人侵者,我们现在与之
作战的仍是人类;但从本质上讲,这些人类的背叛者也可以看成来自地球文明之外的敌人,我们是第一次面对这样的敌人。
下一步的作战目标十分明确,就是要夺取‘审判日’号上被截留的三体信息,这些信息,可能对人类文明的存亡具有重要
意义。
`;
}
}
bootstrap(EzApp);
</script>
</body>
</html>
- 使用分支逻辑
如果组件的模板需要根据某个表达式的不同取值展示不同的片段,可以使用NgSwitch系列指令 来动态切分模板。比如右边示例中的广告组件EzPromotion,需要根据来访者性别的不同推送 不同的广告
引用图片ngswitch.jpg
- NgSwitch
NgSwitch指令可以应用在任何HTML元素上,它评估元素的ngSwitch属性值,并根据这个值 决定应用哪些template的内容(可以同时显示多个分支)
<ANY [ng-switch]="expression">...</ANY>
- NgSwitchWhen
NgSwitchWhen指令必须应用在NgSwitch指令的子template元素上,它通过属性ngSwitchWhen指定一个表达式, 如果该表达式与父节点的NgSwitch指令指定的表达式值一致,那么显示这个template的内容
<ANY [ng-switch]="...">
<!--与变量比较-->
<template [ng-switch-when]="variable">...</template>
<!--与常量比较-->
<template ng-switch-when="constant">...</template>
</ANY>
- NgSwitchDefault
NgSwitchDefault指令必须应用在NgSwitch指令的子template元素上,当没有NgSwitchWhen指令匹配 时,NgSwitch将显示这个template的内容:
<ANY [ng-switch]="...">
<template ng-switch-default>...</template>
</ANY>
*分别类似C语言中的switch case default*
[ng-switch]="sss" ----->类似switch(sss)
ng-switch-when = "aaa" ----> 类似case aaa:
ng-switch-default = "bbb" ---->类似default:
- NgFor循环逻辑
- 迭代
NgFor指令应用在template元素上,对ngForOf属性指定的数据集中的每一项 实例化一个template的内容
<template ng-for [ng-for-of]="items" >
<li>----------</li>
</template>
- 使用数据项
我们还可以为数据集的每一项声明一个局部变量,以便在模板内引用
<template ng-for [ng-for-of]="items" #item>
<li>{{item}}</li>
</template>
- 使用数据项索引
有时还需要数据项在数据集中的索引,我们也可以为数据集的每一项的索引声明一个 局部变量,以便在模板内引用
<template ng-for [ng-for-of]="items" #item #i="index">
<li>[{{i+1}}] {{item}}</li>
</template>
- 语法糖
与NgIf类似,Angular2也为NgFor提供了两种语法糖
//使用template attribute
<ANY template="ng-for #item of items;#i=index">...</ANY>
//使用*前缀
<ANY *ng-for="#item of items;#i=index">...</ANY>
//毫无疑问,应当尽量使用*ng-for的简便写法,这可以提高模板的可读性。
组件开发-为模版应用样式
1. styles -- 设置模版样式
1. 内联样式:
@View({
styles:[
`h1{background:#4dba6c;color:#fff}`
]
})
2. 外联样式:
<!-- myStyle.css -->
h1{
background:#4dba6c;color:#fff;
}
<!--注解使用styleUrls-->
@View({
styleUrls:["myStyle.css"]
})
2. ShadowDom -- 封装私有样式
1. 全局仿真策略
<style>
h1{
color:red;
}
</style>
<body>
<h1>hello world</h1>
<h1>second hello world</h1>
</body>
<!-- 所有h1标签都会相应style中的样式。支持所有浏览器 -->
2. 作用域仿真策略
<style>
h1[tab_h1]{
color:red;
}
</style>
<body>
<h1 tab_h1>hello world</h1>
<h1>second hello world</h1>
</body>
<!-- 只有带有tab_h1属性的h1标签才会响应属性。支持所有浏览器 -->
3. 原生策略
图片引用sd.strategy.jpg
<!-- 该策略需要浏览器支持ShadowDom -->
@Component({selector:"ez-app"})
@View({
template:"<h1>我是H1,我在组件内</h1>",
styles:["h1{color:red}"]
})
class EzApp{}
<!-- 选择EmulatedScopedShadowDomStrategy -->
var injectables = [
bind(ShadowDomStrategy)
.toFactory((doc) => new EmulatedScopedShadowDomStrategy(doc.head), [DOCUMENT_TOKEN])
];
/*
以上的同等写法如下
bind(ShadowDomStrategy).toFactory(function(doc){
return new NativeShadowDomStrategy(doc.head);
},[DOCUMENT_TOKEN])
*/
bootstrap(EzApp,injectables);
组件开发 – 属性和事件
1. 属性声明 - 暴露成员变量
在Angular2中为组件增加属性接口非常简单,只需要在Component注解的 properties属性中声明组件的成员变量就可以了
//EzCard
@Component({
properties:["name","country"]
})
//EzApp
@View({
directives : [EzCard],
template : "<ez-card [name]="'雷锋'" [country]="'中国'"></ez-card>"
})
2. 事件声明 - 暴露事件源
//EzCard
@Component({
events:["change"]
})
class EzCard{
constructor(){
this.change = new EventEmitter();
}
}
//EzApp
@View({
template : "<ez-card (change)="onChange()"></ez-card>"
})
<? 此处有待详细说明 ?>
组件开发 – 表单输入
1. NgForm - 表单指令
//EzApp组件
@Component({selector:"ez-app"})
@View({
directives:[formDirectives,NgIf],
template:`
<!-- 在form中声明submit -->
<form #f="form" (submit)="search(f.value)">
<select>
<option value="web">网页</option>
<option value="news">新闻</option>
<option value="image">图片</option>
</select>
<input type="text" ng-control="kw">
<button type="submit">搜索</button>
</form>
<!--给个简单的反馈-->
<h1 *ng-if="kw!=''">正在搜索 {{kw}} ...</h1>
`,
styles:[`form{background:#90a4ae;padding:5px;}`]
})
class EzApp{
constructor(){
this.kw = "";
}
search(val){
this.kw = val.kw;
//假装在搜索,2秒钟返回
setTimeout(()=>this.kw="",2000);
}
}
bootstrap(EzApp);
2. NgControlName - 命名控件指令
1. 属性ngControl
<form #f="form">
<input type="text" ng-control="user">
<input type="password" ng-control="pass">
</form>
2. 属性/方法:ngModel
<form>
<input type="text" ng-control="user" [(ng-model)]="data.user">
<input type="password" ng-control="pass" [(ng-model)]="data.pass">
</form>
//ngModel即是NgControlName指令的属性,也是它的事件,所以下面 的两种写法是等价的
<input type="text" ng-control="user" [(ng-model)]="data.user">
//等价于
<input type="text" ng-control="user" [ng-model]="data.user" (ng-model)="data.user">
3. NgCongrolGroup - 命名控件组
图片引用ngcg.jpg
@Component({selector:"ez-app"})
@View({
directives:[NgIf,formDirectives],
template:`
<form #f="form">
<p>基本信息</p>
<!--声明控件组-->
<ul ng-control-group="basic">
<li>姓名:<input type="text" ng-control="name"></li>
<li>地址:<input type="text" ng-control="address"></li>
<li>电话:<input type="text" ng-control="telephone"></li>
</ul>
<p>专业技能</p>
<!--声明控件组-->
<ul ng-control-group="expertise">
<li>英语:<input type="checkbox" ng-control="english"></li>
<li>科技:<input type="checkbox" ng-control="tech"></li>
<li>运动:<input type="checkbox" ng-control="sport"></li>
</ul>
</form>
<!--调试:实时转储模型的值-->
<pre>{{decode(f.value)}}</pre>
`,
styles:[`
p{padding:5px;background:#b3e5fc;color:red;}
form{background:#e1f5fe;}
ul{list-style:none;padding:5px;margin:0px;}
li{line-height:30px;}
`]
})
class EzApp{
decode(val){
return JSON.stringify(val,null,"\t");
}
}
bootstrap(EzApp);
4. NgFormControl - 绑定已有控件对象
@View({
//将输入元素绑定到已经创建的控件对象上
template : `<input type="text" [ng-form-control]="movie">`
})
class EzComp{
constructor(){
//创建控件对象
this.movie = new Control("Matrix II - Reload");
}
}
实例代码
@Component({selector:"ez-app"})
@View({
directives:[formDirectives],
template:`
<p>
<ul>
<!--将输入元素绑定到已经创建的控件对象-->
<li>姓名:<input type="text" [ng-form-control]="name"></li>
<li>地址:<input type="text" [ng-form-control]="address"></li>
<li>电话:<input type="text" [ng-form-control]="telephone"></li>
</ul>
</p>
<!--调试:转储模型信息-->
<pre>{{dump()}}</pre>
`,
styles:[`
form{background:#e1f5fe;}
ul{list-style:none;padding:10px;margin:0px;}
li{line-height:30px;}
`]
})
class EzApp{
constructor(){
//创建控件对象
this.name = new Control("Jason");
this.address = new Control("London U.K.");
this.telephone = new Control("114");
}
dump(){
//读取控件对象的值
var val = {
name : this.name.value,
address : this.address.value,
telephone : this.telephone.value
}
return JSON.stringify(val,null,"\t");
}
}
bootstrap(EzApp);
5. NgFormModel - 绑定已有控件组
//简单示例
@View({
template : `
<!--绑定控件组与控件对象-->
<p [ng-form-model]="controls">
<input type="text" ng-control="name">
<input type="text" ng-control="age">
</p>`
})
class EzComp{
constructor(){
//创建控件组及控件对象
this.controls = new ControlGroup({
name :new Control("Jason"),
age : new Control("45")
});
}
}
实例项目
@Component({selector:"ez-app"})
@View({
directives:[formDirectives],
template:`
<p [ng-form-model]="controls">
<ul>
<li>姓名:<input type="text" ng-control="name"></li>
<li>地址:<input type="text" ng-control="address"></li>
<li>电话:<input type="text" ng-control="telephone"></li>
</ul>
</p>
<pre>{{dump()}}</pre>
`,
styles:[`
p{background:#e1f5fe;}
ul{list-style:none;padding:10px;margin:0px;}
li{line-height:30px;}
`]
})
class EzApp{
constructor(){
this.controls = new ControlGroup({
name : new Control("Jason"),
address : new Control("London U.K."),
telephone : new Control("114")
});
}
dump(){
return JSON.stringify(this.controls.value,null,"\t");
}
}
bootstrap(EzApp);
组件开发 – 调用服务
1. 服务 - 封装可复用代码
在Angular2中,服务用来封装可复用的功能性代码。比如Http服务,封装了ajax 请求的细节,在不同的组件中,我们只需要调用Http服务的API接口就可以给组件增加 ajax请求的功能了
//定义一个简单的算法服务
class EzAlgo{
add(a,b) { return a+b; }
sub(a,b) { return a-b; }
}
//组件定义
@Component({
selector : "ez-app"
})
@View({
directives:[formDirectives],
template : `
<form>
<input type="text" ng-control="a" [(ng-model)]="a">
+
<input type="text" ng-control="b" [(ng-model)]="b">
=
{{add()}}
</form>`
})
class EzApp{
constructor(){
this.a = 37;
this.b = 128;
//实例化服务对象
this.algo = new EzAlgo();
}
add(){
var a = this.a,
b = this.b;
return this.algo.add(a,b);
}
}
bootstrap(EzApp);
2. 注入 - appInjector
//简单叙述
@Component({
selector : "ez-app",
//声明依赖
appInjector : [EzAlgo]
})
@View(...)
class EzApp{
//Angular2框架负责注入对象
constructor(@Inject(EzAlgo) algo){
//已经获得EzAlgo实例了!
}
}
//不使用appInjector,使用bootstrap也可以实现注入
bootstrap(EzApp,EzAlgo);//EzAlgo,类名
3. 注入一个复杂的服务
<? 此处还需仔细思考 ?>
//引入Http相关预定义类型
import {Http,httpInjectables} from "angular2/http";
//EzApp组件
@Component({
selector:"ez-app",
//注入Http依赖项集合
appInjector:[httpInjectables]
})
@View({
directives:[NgFor],
template:`
<p *ng-for="#album of band.albums"><img [src]="album.cover"></p>
`,
styles:[`
img{height:200px;width:200px;}
p{float:left;margin:10px;}
`]
})
class EzApp{
//注入Http实例对象
constructor(@Inject(Http) http){
this.band = {};
http.get("api/music.json")//GET请求
.map(rsp=>rsp.json())//将相应转化为JSON格式的数据集
.subscribe(data=>this.band=data[0]);//设置band变量为数据集的第一项
}
}
bootstrap(EzApp);
组件路由 – 原理与应用
1. 路由初体验
//引入路由相关类型定义
import {LocationStrategy,RouteConfig,RouterOutlet,RouterLink,Router,routerInjectables} from "angular2/router";
//EzApp组件 : 路由配置与执行
@Component({selector:"ez-app"})
@View({
directives:[RouterOutlet,RouterLink],
template : `
<nav>
<!--声明路由入口-->
<b router-link="video">video</b> |
<b router-link="music">music</b>
</nav>
<main>
<!--声明路由出口-->
<router-outlet></router-outlet>
</main>
`
})
//路由配置
@RouteConfig([
{path:"/video", component:EzVideo,as:"video"},
{path:"/music", component:EzMusic,as:"music"}
])
class EzApp{
constructor(@Inject(LocationStrategy) ls){
ls.pushState = function(){};//simple hack for crash bug.
}
}
//EzVideo组件
@Component({selector:"ez-video"})
@View({
template : `
<h3>视频:轻松一刻</h3>
<embed allowscriptaccess="always" height="482" pluginspage="https://get.adobe.com/cn/flashplayer/" flashvars="list=http%3A%2F%2Fus.sinaimg.cn%2F002TFmqWjx06TNSxqGuz0504010000220k01.m3u8%3FKID%3Dunistore%2Cvideo%26Expires%3D1437020410%26ssig%3DNnoWLSjm2v&fid=1034:882b42973162c7ae7acef23bfaccbe8c&logo=2&uid=1971237631" allowfullscreen="true" width="482" quality="high" src="https://js.t.sinajs.cn/t5/album/static/swf/video/player.swf?v1423545453000454353" type="application/x-shockwave-flash" wmode="transparent">
`
})
class EzVideo{}
//EzMusic组件
@Component({selector:"ez-music"})
@View({
template : `
<h3>音乐:平凡之路</h3>
<embed src="https://player.yinyuetai.com/video/player/2094298/a_0.swf" quality="high" width="480" height="334" align="middle" allowScriptAccess="sameDomain" allowfullscreen="true" type="application/x-shockwave-flash"></embed> `
})
class EzMusic{}
//注入路由功能依赖项
bootstrap(EzApp,[routerInjectables]);
2. 路由 - 应用步骤
1.配置路由
router.config([
{path:"/video", component:EzVideo},
{path:"/music", component:EzMusic}
])
//上面的代码中,配置了两条路由:
//1.如果用户请求路径为/video,那么将在路由出口中激活组件EzVideo
//2.如果用户请求路径为/music,那么将在路由出口中激活组件EzMusic
2. 设置路由出口
@View({
directives:[RouterOutlet],
//设置路由出口
template : `<router-outlet></router-outlet>`
})
class EzApp{...}
3. 执行路由
@View({
template : `
<span (click)="router.navigate('/video')">video</span> |
<span (click)="router.navigate('/music')">music</span>
<router-outlet></router-outlet>`
})
//我们向navigate()方法传入的路径,就是我们通过config()方法配置的路径。这样, Router就根据这个路径,找到匹配的组件,在RouterOutlet上进行激活。
4. 开始路由前,需要的准备工作
// 1. 引用路由包
<script type="text/javascript" src="lib/router.dev.js"></script>
// 2. 引入路由相关的预定义类型
import {LocationStrategy,Router,RouterOutlet,routerInjectables} from "angular2/router";
// 3. 声明路由相关依赖类型
bootstrap(EzApp,[routerInjectables]);
//简易项目代码
import {Inject,Component,View,bootstrap} from "angular2/angular2";
import {LocationStrategy,RouterOutlet,Router,routerInjectables} from "angular2/router";
@Component({selector:"ez-app"})
@View({
directives:[RouterOutlet],
template : `
<nav>
<b (click)="go('/video')">video</b> |
<b (click)="go('/music')">music</b>
</nav>
<main>
<!--声明路由出口-->
<router-outlet></router-outlet>
</main>
`
})
class EzApp{
constructor(@Inject(Router) rt,@Inject(LocationStrategy) ls){
ls.pushState = function(){};
this.router = rt;
//配置路由
this.router.config([
{path:"/video", component:EzVideo},
{path:"/music", component:EzMusic}
]);
}
go(path){
//根据给定的url,选中组件并在outlet中激活
this.router.navigate(path);
}
}
@Component({selector:"ez-video"})
@View({
template : `
<h1>I LOVE THIS VIDEO!</h1>
`
})
class EzVideo{}
@Component({selector:"ez-music"})
@View({
template : `
<h1>THAT'S FANTASTIC MUSIC!</h1>
`
})
class EzMusic{}
bootstrap(EzApp,[routerInjectables]);
3. RouteConfig - 路由配置注解

@RouteConfig([
{path:"/video", component:EzVideo},
{path:"/music", component:EzMusic}
])
class EzApp{...}
4. RouterLink - 路由入口指令
//RouterLink并不能直接使用路由项的路径,router-link属性 的值是一个路由项的别名,我们需要在路由配置时通过as属性,为路由项设定别名
@RouteConfig([
{path:"/video", component:EzVideo , as:"video"},
{path:"/music", component:EzMusic , as:"music"}
])
@View({
directives:[RouterOutlet,RouterLink]
template : `<nav>
<b router-link="video">video</b> |
<b router-link="music">music</b>
</nav>
<router-outlet></router-outlet>`
})
5. RouteRegistry - 路由注册表

1. 匹配表/matchers
@RouteConfig([
{path:"/video", component:EzVideo},
{path:"/music", component:EzMusic}
])
2. 重定向表/redirects
@RouteConfig([
{path:"/video", component:EzVideo},
{path:"/music", component:EzMusic},
{path:"/test", redirectTo:"/video"}
])
3.名称表/names
@RouteConfig([
{path:"/video", component:EzVideo,as:"video"},
{path:"/music", component:EzMusic,as:"music"}
])