anjular快速入门
转载:https://zhuanlan.zhihu.com/p/27696268。本部分为其简洁版。
模块
anjular的一个应用至少要有一个模块,也就是根模块。一些共享的属性我们可以抽象出来,成为共享模块,然后就是一些特性模块了。模块的组成由组件,服务,指令,管道等等组成。
模块的定义语法:
@NgModuel({
declarations: [], // 用到的组件,指令,管道
providers: [], // 依赖注入服务
imports: [], // 导入需要的模块
exports: [], // 导出的模块,跨模块交流
entryComponents: [] // 需提前编译好的模块
bootstrap: [] // 设置根组件
})
export class AppModule {
}
一般情况下,在根模块的bootstrap中设置启动的根组件即可,但也可以动态处理。
如何启动根模块?在入口脚本
中,也就是Angular Cli项目中的main.ts
中,启动如下:
// 导入需要模块
import {
platformBrowserDynamic } from '@angular/platform-browser-dynamic';
// 根模块
import {
AppModule } from './app/app.module';
// 编译启动模块
platformBrowserDynamic().bootstrapModule(AppModule);
组件
Angular的核心概念是组件,模块化机制NgModule是为组件化服务的, 组件通常都是由模版和业务逻辑组成。
如何用Angular写一个很简单的组件?如下。
// hello.component.ts
import {
Component } from '@angular/core';
@Component({
selector: 'hello',
template: '<p> {
{greeting}} </p>',
styles: [`p { color: red;}`]
})
export class HelloComponent{
private greeting: string;
constructor(){
this.greeting = 'Hello, Angular2!';
}
}
// 使用
<hello></hello>
// 渲染结果
<hello>
<p> Hello, Angular2! </p>
</hello>
定义类HelloComponent的时候,加上装饰器@Component(
Typescript语法),告诉Angular这个类是组件类,里面
的数据称之为元数据(metadata)
,selector属性
说明了该组件对外的使用标记
,template
就是组件的模版
,styles
是组件的样式
。而HelloComponent中定义的就是该组件的业务逻辑
了。
组件生命周期
正如其他框架的组件,Angular的组件也是有生命周期这个概念。
constructor:构造器函数,一般用于注入服务
ngOnChanges:检测到输入数据变化,首次触发发生在ngOnInit前。注意对象的属性发生变化时监听不到
ngOnInit:组件初始化,通常会设置一些初始值
ngDoCheck:手动触发更新检查
- ngAfterContentInit:内容初始化到组件之后
- ngAfterContentChecked:内容变更检测之后
- ngAfterViewInit:视图 初始化之后
- ngAfterViewChecked:视图发生变化检测之后,这个可以用来保证用户视图的及时更新
ngOnDestroy:组件注销时的清理工作,通常用于移除事件监听,退订可观察对象等
组件间通信
主要介绍父子组件之间的参数传递问题。
- 父组件到子组件
父组件用属性绑定
将值传入,子组件通过@Input
来接收。 - 子组件到父组件
子组件自定义事件用@Output
传出,父组件用事件绑定
获取。 - 子组件引用
在父组件模版中添加对子组件的引用,即可通过该子组件去访问子组件的方法。 - @ViewChild()
类似的,也可以在脚本中用@ViewChild()来获取子组件。 - 将数据保存在服务中
- @ngrx/store
模板与数据绑定
- 插值绑定
双花括号{ {}} - 属性(Property)绑定
<input [value]='myData'>
- 样式绑定
<div [ngClass]="{special: isSpecial}"></div>
- 事件绑定
<input (keyup)='handle($event)' >
- 双向绑定
<input [(ngModel)] = 'data'> // 双向绑定的背后其实是单向绑定和事件触发,等价于下面 <input [ngModel]="data" (ngModelChange)="data=$event">
- 模版引用变量(# / ref-)
可以在元素上用#或者ref-前缀来标记这个元素,然后在其他地方引用。<input #fax placeholder="fax number"> ( <input ref-fax placeholder="fax number"> ) <button (click)="callFax(fax.value)">Fax</button>
- *ngIf:控制内容的有无
如果还有else部分,可以如下操作:<div *ngIf="show"> Can you see this? </div>
<div *ngIf="show; else elseBlock"> Can you see this? </div> <ng-template #elseBlock> else block </ng-template>
- *ngFor:循环
<div *ngFor="let hero of heroes; let i=index> { { i}}: { { hero.name}}</div>
路由
一个模块有了多个组件之后,需要用路由来配置哪个url呈现哪个组件。具体步骤
- 首先,我们需要在入口页面的index.html中配置根路径;
- 然后创建一个路由模块;
- 在主模块中导入配置好的路由模块;
- 而在页面中需要一个容器去承载;
注意:
- 路由上还可以带上一些索引参数:
获取的方式:{ path: 'heroes/:id', component: HeroesComponent },
import { ActivatedRoute, Params } from '@angular/router'; ... export class a { constructor( private route: ActivatedRoute ) { } // 路由参数 this.route.params }
- 懒加载
当模块很多,路由也很多的时候,我们可以使用模块懒加载的方式。懒加载的方式也很简单,在配置路由的时候修改如下即可:const routes: Routes = [ { // 默认转到订单管理 path: '', redirectTo: '/order', pathMatch: 'full' }, { path: 'order', loadChildren: './order/order.module#OrderModule' }, { path: 'warehouse', loadChildren: './warehouse/warehouse.module#WarehouseModule' }, { path: 'statistics/sales', component: SalesComponent } ]; // 在子模块中用RouterModule.forChild import { NgModule } from '@angular/core'; import { RouterModule } from '@angular/router'; import { OrderComponent } from './order.component'; const orderRoutes = [ { path:'', component: OrderComponent } ]; @NgModule({ imports: [RouterModule.forChild(orderRoutes)], exports: [RouterModule] }) export class OrderRoutingModule { }
服务与依赖注入
服务
是什么概念?可以简单地认为它是一个功能模块,重要在于它是单例对象,并且可以注入到其他的地方使用。
依赖注入
是来自后端的概念,其实就是自动创建一个实例,省去每次需要手动创建的麻烦。
- 在类之前加上@Injectable装饰器的功能。
- 在模块的providers中声明。
- 使用的时候需要在构造器中建立关联。
指令
- 组件指令
组件指令是用指令的方式去写组件。 - 属性指令
属性指令只改变元素的样式或者行为。 - 结构指令
结构指令就是模板中提到的*ngIf,ngFor等指令,它修改了DOM结构。
管道
管道其实就是过滤器,就是叫法不一致而已。主要用于格式化源数据,而不改变源数据。Angular内置了一些管道。
自定义管道和使用的方式如下:
- 定义:
import { Pipe, PipeTransform } from '@angular/core'; /* * 订单取消状态:默认为ALL表示全部,CANCEL表示已取消,NOTCANCEL表示正常 */ @Pipe({ name: 'cancelStatus' }) export class CancelStatusPipe implements PipeTransform { transform(status:string, blank: boolean):string { const map = { "ALL": "全部", "NOTCANCEL": "正常", "CANCEL": "已取消", "": "暂无", } return blank? '特殊情况': map[status]; } }
- 使用
使用前记得在模块的declarations声明,或者导到共享模块,在共享模块中导出去。{ { "ALL" | cancelStatus }} // 全部 { { "ALL" | cancelStatus: true }} // 特殊情况
anjular部分语法备忘
@NgModule
NgModule 最根本的意义是帮助开发者组织业务代码,开发者可以利用 NgModule 把关系比较紧密的组件组织到一起,这是首要的。
NgModule 用来控制组件、指令、管道等的可见性,处于同一个 NgModule 里面的组件默认互相可见,而对于外部的组件来说,只能看到 NgModule 导出( exports )的内容,这一特性非常类似 Java 里面 package 的概念。也就是说,如果你定义的 NgModule 不 exports 任何内容,那么外部使用者即使 import 了你这个模块,也没法使用里面定义的任何内容。
[ngClass]
NgClass 通过接收行内申明或者来自 typescript 类的 属性/方法 的方式获取输入内容。