大三上学期,在学校实验室自学的angular1,如今马上毕业了,公司里已经用上了angular5。学起来!!!
组件、服务、路由、指令
当然,angular5是建立在node6.9版本和npm3.3版本以这两个上的。先全局安装这两个软件吧。
全局安装angular5脚手架。Angular CLI :npm install -g @angular/cli
运行下列命令来生成一个新项目以及应用的骨架代码:ng new my-app (需要耐心等待)
cd my-app
ng serve --open
ng serve
命令会启动开发服务器,监听文件变化,并在修改这些文件时重新构建此应用。
使用--open
(或-o
)参数可以自动打开浏览器并访问http://localhost:4200/
。
这个CLI为我们创建了第一个Angular组件。 它就是名叫app-root
的根组件。 你可以在./src/app/app.component.ts
目录下找到它。
浏览器会自动刷新,而我们会看到修改之后的标题。不错,不过它还可以更好看一点。
打开 src/app/app.component.css
并给这个组件设置一些样式
Angular CLI项目是做快速试验和开发企业解决方案的基础。
scr文件夹:你的应用代码位于src
文件夹中。 所有的Angular组件、模板、样式、图片以及你的应用所需的任何东西都在那里。 这个文件夹之外的文件都是为构建应用提供支持用的。
根目录:src/
文件夹是项目的根文件夹之一。 其它文件是用来帮助你构建、测试、维护、文档化和发布应用的。它们放在根目录下,和src/
平级。
使用 Angular CLI 创建一个名为 heroes
的新组件。ng generate component heroes
CLI 创建了一个新的文件夹 src/app/heroes/
,并生成了 HeroesComponent
的三个文件。
CLI 自动生成了三个元数据属性:@component是一个装饰器,告诉文件中的typescript的类这是一个组件
selector
— 组件的选择器(CSS 元素选择器)
templateUrl
— 组件模板文件的位置。
styleUrls
— 组件私有 CSS 样式表文件的位置。
控制器:
typescript类定义了组件的控制器,是一个被装饰器装饰的typescript的类
ngOnInit
是一个生命周期钩子,Angular 在创建完组件后很快就会调用 ngOnInit
。这里是放置初始化逻辑的好地方。
始终要 export
这个组件类,以便在其它地方(比如 AppModule
)导入它。
例如安装:jQuery和bootstrap
npm install jquery --save
npm install bootstrap --save
修改angular CLI.json文件,scripts属性和css属性中添加文件路径
因为jQuery是JavaScript的文件,typescript文件是不认识$符号的。所以要在项目中引入类型描述文件
输入命令:npm install @types/jquery --save-dev npm inastall @types/bootstrap --save-dev
往 HeroesComponent
中添加一个 hero
属性,用来表示一个名叫 “Windstorm” 的英雄。
hero = 'Windstorm';
几种定义属性的方法
//定义属性的方法
title='你好angular';
//定义属性的方法2
msg:any;
msg1:string='这是一个string类型的msg1'; //定义类型并且赋值
//定义属性加修饰符
public username="张三"
constructor(){
this.msg='这是定义属性方法2'
}
绑定属性的方法
要显示 HeroesComponent
你必须把它加到壳组件 AppComponent
的模板中。
别忘了,app-heroes
就是 HeroesComponent
的 元素选择器。 所以,只要把
元素添加到 AppComponent
的模板文件中就可以了,就放在标题下方。
在 src/app
文件夹中为 Hero
类创建一个文件,并添加 id
和 name
属性。
export class Hero { id: number; name: string;}
回到 HeroesComponent
类,并且导入这个 Hero
类。
把组件的 hero
属性的类型重构为 Hero
。 然后以1
为 id
、以 “Windstorm” 为名字初始化它。
import { Component, OnInit } from '@angular/core';
import { Hero } from '../hero';
@Component({
selector: 'app-heroes',
templateUrl: './heroes.component.html',
styleUrls: ['./heroes.component.css']
})
export class HeroesComponent implements OnInit {
hero: Hero = {
id: 1,
name: 'Windstorm'
};
constructor() { }
ngOnInit() {
}
}
页面显示变得不正常了,因为你刚刚把 hero
从字符串改成了对象。
修改模板中的绑定,以显示英雄的名字,并在详情中显示 id
和 name
,就像这样:
把 hero.name
的绑定修改成这样:
{{ hero.name | uppercase }} Details
管道
是格式化字符串、金额、日期和其它显示数据的好办法。 Angular 发布了一些内置管道,而且你还可以创建自己的管道。
2.3双向数据绑定
[(ngModel)] 是 Angular 的双向数据绑定语法。([(ngModel)] 不可以改变)
这里把 hero.name
属性绑定到了 HTML 的 textbox 元素上,以便数据流可以双向流动:从 hero.name
属性流动到 textbox,并且从 textbox 流回到 hero.name
。
缺少formsmodule,实现双向数据绑定需要引入formsmodule模块,还要在app.modules导入
虽然 ngModel
是一个有效的 Angular 指令,不过它在默认情况下是不可用的。
它属于一个可选模块FormsModule
,你必须自行添加此模块才能使用该指令。
导入formsmodule
打开 AppModule
(app.module.ts
) 并从 @angular/forms
库中导入 FormsModule
符号。
import { FormsModule } from '@angular/forms'; // <-- NgModel lives here
然后把
FormsModule
添加到
@NgModule
元数据的
imports
数组中,这里是该应用所需外部模块的列表。
imports: [
BrowserModule,
FormsModule
],
每个组件都必须声明在(且只能声明在)一个 NgModule 中。
2.4事件对象表单处理
//事件对象
//键盘弹起
keyupFn(e){
console.log(e);
if(e.keyCode==13){ //键盘回车键keycode
alert('按下回车键');
}
}
3、创建模拟数据
创建模拟mock数据
显示这些数据
你要在 HeroesComponent
的顶部显示这个英雄列表。
打开 HeroesComponent
类文件,并导入模拟的 HEROES
。
import { HEROES } from '../mock-heroes';
往类中添加一个 heroes
属性,这样可以暴露出这些英雄,以供绑定。
heroes = HEROES;
使用*ng-for使用这些数据
-
{{hero.id}} {{hero.name}}
*ngFor
是一个 Angular 的复写器(repeater)指令。 它会为列表中的每项数据复写它的宿主元素。
在这个例子中
就是
*ngFor
的宿主元素
heroes
就是来自 HeroesComponent
类的列表。
当依次遍历这个列表时,hero
会为每个迭代保存当前的英雄对象。
4、主从结构
添加click事件绑定
这是 Angular 事件绑定 语法的例子。
click
外面的圆括号会让 Angular 监听这个 元素的
click
事件。 当用户点击 时,Angular 就会执行表达式
onSelect(hero)
。
onSelect()
是 HeroesComponent
上的一个方法,你很快就要写它。 Angular 会把所点击的 上的
hero
对象传给它,这个 hero
也就是以前在 *ngFor
表达式中定义的那个。
添加click事件处理器
5、服务
为什么需要服务?:把数据访问的职责委托给服务。
创建一个heroserives服务,应用中所有的类都可以利用他来获取英雄列表。不用使用new来创建此服务,而要依靠angular的依赖注入机制把它注入到 HeroesComponent
的构造函数中。
服务是在多个“互相不知道”的类之间共享信息的好办法。 你将创建一个 MessageService
,并且把它注入到两个地方:
HeroService
中,它会使用该服务发送消息。
MessagesComponent
中,它会显示其中的消息。
创建服务命令:
例如:使用 Angular CLI 创建一个名叫 hero
的服务。ng generate service hero
注意:依赖注入服务写到括号里面不是花括号里面。
@injectable()服务
在服务文件中创建服务
在模板组件中使用服务
HeroService.getHeroes()
必须具有某种形式的异步函数签名。
它可以使用回调函数,可以返回 Promise
(承诺),也可以返回 Observable
(可观察对象)。
Observable(可观察对象)版本的HeroService
Observable
是 RxJS 库中的一个关键类。
可以把路由器理解:为控制整个应用视图状态的对象,每个应用都有一个路由器,配置路由器以满足需求。
为每个视图分配一个特定的URL,这样就可以是应用直接跳到某个特定的视图中。
加载和配置路由器,他专注于路由功能,然后由根模块导入它APPModule。
ng generate module app-routing --flat --module=app
--flat
把这个文件放进了
src/app
中,而不是单独的目录中。
--module=app
告诉 CLI 把它注册到
AppModule
的
imports
数组中。
通常不会在路由模块中声明组件
Routes对象:
注意:path变量中不能加入斜杠开头,因为angular路由器会为我们解析生成URL,不使用斜杠开头可以自由的用绝对路径和性对路径来切换。
Router对象:
RouterOutlet:(插座)指示当前某一个导航的路由的时候,组件视图显示的地方。
routerLink对象: 跟路由
在路由时传递数据:
1.在查询参数种传递数据
/product?id=1&name=2 => ActivaedRoute.queryParams[id];
举例:
商品详情
export class ProductComponent implements OnInit {
private productId: number;
constructor(private routerInfo: ActivatedRoute) { }
ngOnInit() {
this.productId = this.routerInfo.snapshot.queryParams['id'];
}
}
2.在路由路径(URL)中传递数据??? 小练习中不能实现
{path:/product/:id} => /product/1 => ActivatedRoute.params[id]
举例:
export class ProductComponent implements OnInit {
private productId: number;
constructor(private routerInfo: ActivatedRoute) { }
ngOnInit() {
this.productId = this.routerInfo.snapshot.params['id'];
}
}
商品详情
app-routingcomponent
{path: 'product/id', component: ProductComponent}, // 修改路由中的path属性使其可以携带参数
3.路由配置中传递数据
{path:/product, component:ProductComponent,data:[{isProd:true}]}
=> ActivatedRoute.data[0][isProd]
参数快照:
private productId: number;
constructor(private routerInfo: ActivatedRoute) { }
ngOnInit() {
this.productId = this.routerInfo.snapshot.params['id'];
}
参数订阅:
ngOnInit() {
this.routerInfo.params.subscribe((params: Params) => this.productId = params["id"]);
this.productId = this.routerInfo.snapshot.params['id'];
}
重定向路由
在用户访问一个特定的地址时,将其重定向到另一个指定的地址。
// 路由重定向,重定向到home的路由上
{path: '', redirectTo: '/home', pathMatch: 'full'},
{path: 'home', component: HomeComponent},
子路由
辅助路由:
//路由配置
{path:'xxx',comment:XxxComponent,outlet:"aux"}
{path:'yyy',comment:yyyComponent,outlet:"aux"}
//链接
xxx
yyy
路由守卫:
应用场景:例如
CanActivate:处理导航到某路由的情况。
CanDeactivate:处理当前路由离开的情况。
Resolve:在路由激活之前获取路由数据。
Resolve:
可以预先在进入路由之前去服务器上读数据,把需要的数据带到视图里面显示出来
需要使用RouterModule中的Routes类来配置路由器,所以还需要从@angular/router库中导入这两个符号。
添加一个@ngModule.exports数组,其中放上RouterModule.
导出RouterModule路由器的相关指令,可以在APPModule中的组件使用。
典型的 Angular 路由(Route
)有两个属性:
path
:一个用于匹配浏览器地址栏中 URL 的字符串。
component
:当导航到此路由时,路由器应该创建哪个组件。
HeroesComponent
,以便能在
Route
中引用它。 然后定义一个路由数组,其中的某个路由是指向这个组件的。
import { HeroesComponent } from './heroes/heroes.component';
const routes: Routes = [
{ path: 'heroes', component: HeroesComponent }
];
RouterModule.forRoot()
必须先初始化路由器,并让开始监听浏览器的地址变化
把RouterModule,添加到@ngimports数组中,并用routes来配置。只需要调用imports数组中的RouterModule.forRoot()函数就可以了。
添加路由出口RouterOutLet
7、HTTP
启动http服务
httpclient是angular通过http与远程服务的机制。
模拟数据服务
通过httpclient获取英雄
http方法返回单个值
所有的httpclient都会返回某个值的RxJSobservable
http是一个请求响应协议,你发送请求他返回单个的响应
httpclient.get返回响应数据
HttpClient.get
默认情况下把响应体当做无类型的 JSON 对象进行返回。 如果指定了可选的模板类型
,就会给返回你一个类型化的对象。
错误处理
凡事皆会出错,特别是当你从远端服务器获取数据的时候。 HeroService.getHeroes()
方法应该捕获错误,并做适当的处理。
要捕获错误就要使用RXJS的catchError操作符来建立对observable的结果处理的管道。
catchError()
操作符会拦截失败的Observable
。 它把错误对象传给错误处理器,错误处理器会处理这个错误。
下面的 handleError()
方法会报告这个错误,并返回一个无害的结果(安全值),以便应用能正常工作。
如果你忘了调用 subscribe()
,本服务将不会把这个删除请求发送给服务器。 作为一条通用的规则,Observable
在有人订阅之前什么都不会做。
8、模板与数据绑定
8.1 显示数据
最典型的数据显示方式就是把html中的模板中的控件绑定到angular组件的属性。
使用插值表达式显示组件属性
使用差值表达式就是把属性名包裹在双花括号里放进视图模板。
使用ng-for,显示数组属性
为数组创建一个类:
对对象数组的绑定,需要把数组抓换成对象数组
使用该
8.2模板语法
组件扮演着控制器或视图模型的角色,模板则扮演视图的角色
通过数据绑定来动态获取/设置dom对象的
对花括号中的表达式求职,把求职的结果转化成字符串。
模板表达式:
模板表达式产生一个值,并把它赋值给绑定属性的目标。
typescript和JavaScript的区别
JavaScript 中那些具有或可能引发副作用的表达式是被禁止的,包括:
赋值 (=
, +=
, -=
, ...)
new
运算符
使用 ;
或 ,
的链式表达式
自增或自减操作符 (++
和 --
)
和 JavaScript 语 法的其它显著不同包括:
不支持位运算 |
和 &
具有新的模板表达式运算符,比如 |
、?.
和 !
。
表达式上下文
表达式的上下文可以包括组件之外的对象。 比如模板输入变量 (let hero
)和模板引用变量(#heroInput
)就是备选的上下文对象之一。
表达式指南:
没有可见的副作用,除了目标属性值以外不应该改变应用的任何状态。
模板语句:
模板语句用来绑定由绑定目标出发的事件
语句上下文
模板语句不能引用全局命名空间的任何东西,比如不能引用window或document
绑定的类型可以根据数据数据流的方向分成三类,
从数据源到视图:
从视图到数据源:
从视图到数据再到视图:
模板是通过property和事件来工作的,而不是anttribute
绑定目标:
属性绑定:属性名
最常见的属性绑定是把元素的属性设置为组件的属性,
还有重要一种是设置自定义组件的模型属性
单项输入
绑定目标:目标的名字总是property的名
一次性字符串初始化
属性绑定还是差值表达式?但数据类型不是字符串时,就必须使用属性绑定了。要渲染的是字符串时两种都可以。
css绑定?
样式绑定:
通过绑定可以设置内联样式:样式绑定与属性绑定类似
事件绑定:
反向数据流:从元素到组件。左侧带圆括号的目标事件和右侧引号中的模板事件。
目标事件:
$event和事件处理语句
事件绑定中angular回为目标事件设置事件处理器。绑定会通过$event事件对象来传递信息。
事件对象的形态取决于目标事件
双向数据绑定:
双向数据绑定语法:盒子里的香蕉
内置指令:
内置属性型指令:
ng-class:
ng-style:可以根据组件的样式动态设置,可以同时设置多个内联样式:
ng-model:使用之前需要导入formsmodule,并添加到imports列表中
内置结构型指令:
结构性指令的职责是html布局:
ng-if:
通过把ng-if指令应用到元素上称为宿主元素,往dom中添加或从dom中移除这个元素。
这和显示和隐藏式不同的。
当隐藏子树时,它仍然留在 DOM 中。 子树中的组件及其状态仍然保留着。 即使对于不可见属性,Angular 也会继续检查变更。 子树可能占用相当可观的内存和运算资源。
可以用来防范空指针错误。?什么是空指针错误
ngforof:
是一个重复器指令,-自定义数据显示的一种方式 。目标是展示由多个条目组成的列表。
带索引的ng-for
ng-switch:
他可以从多个可能的元素中根据switc hh条件来显示某一个。只会把选中的加入到dom元素中。
主控指令,要把它保存到一个返回候选值得表达式,
绑定到 [ngSwitch]
。如果试图用 *ngSwitch
的形式使用它就会报错,这是因为 NgSwitch
是一个属性型指令,而不是结构型指令。 它要修改的是所在元素的行为,而不会直接接触 DOM 结构。
绑定到 *ngSwitchCase
和 *ngSwitchDefault
NgSwitchCase
和 NgSwitchDefault
指令都是结构型指令,因为它们会从 DOM 中添加或移除元素。
模板引用变量:
模板引用变量通常用来引用模板中的某个dom元素,
模板引用变量怎么得到他的值?
模板引用变量的作用范围是整个模板,不要在同一模板中多次定义同一变量名
输入和输出属性:
输入属性是一个带有input装饰器的可设置属性。
//事件对象
//键盘弹起
keyupFn(e){
console.log(e);
if(e.keyCode==13){ //键盘回车键keycode
alert('按下回车键');
}
}