Angular 开发指南:组件、数据绑定、指令、服务、HTTP、路由和表单
在这篇文章中,我们将深入探讨 Angular 开发中的一些核心概念和常用技术,包括组件、数据绑定、指令、服务、HTTP 客户端、路由和表单。通过这些知识,你将能够构建强大和灵活的 Angular 应用程序。
1. 组件 (Components)
Angular 中的组件类似于 Vue 和 React 中的组件。它们是应用的基本构建块,包含模板、样式和逻辑。
组件装饰器
使用 @Component
装饰器定义组件。
typescript
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'my-angular-app';
}
模板
使用 HTML 文件定义组件的模板。
html
<h1>{{ title }}</h1>
2. 数据绑定 (Data Binding)
Angular 提供了多种数据绑定方式,包括插值绑定、属性绑定、事件绑定和双向绑定。
插值绑定
使用 {{ }}
语法绑定数据到模板。
html
<h1>{{ title }}</h1>
属性绑定
使用 []
语法绑定属性。
html
<img [src]="imageUrl">
事件绑定
使用 ()
语法绑定事件。
html
<button (click)="handleClick()">Click me</button>
双向绑定
使用 [()]
语法实现双向绑定。
html
<input [(ngModel)]="username">
3. 指令 (Directives)
指令是用于操作 DOM 的特殊标记。Angular 提供了结构指令和属性指令。
结构指令
使用 *
语法,如 *ngIf
和 *ngFor
。
html
<div *ngIf="isVisible">Visible content</div>
<ul>
<li *ngFor="let item of items">{{ item }}</li>
</ul>
属性指令
使用 []
语法,如 ngClass
和 ngStyle
。
html
<div [ngClass]="{'active': isActive}">Styled content</div>
4. 常用 ng
命令
Angular CLI 提供了一系列常用命令来帮助开发者创建、构建、测试和维护 Angular 应用程序。
项目创建和初始化
bash
ng new my-app
cd my-app
生成代码
bash
ng generate component my-component
ng generate service my-service
ng generate module my-module
ng generate directive my-directive
ng generate pipe my-pipe
ng generate guard my-guard
开发和构建
bash
ng serve
ng build
ng build --prod
测试
bash
ng test
ng e2e
其他命令
bash
ng update
ng version
ng help
5. 生命周期钩子 (Lifecycle Hooks)
Angular 提供了一系列生命周期钩子,允许你在组件的不同生命周期阶段执行特定的操作。
ngOnChanges
: 当 Angular 设置或重新设置数据绑定输入属性时调用。ngOnInit
: 在 Angular 初始化组件或指令的输入属性之后调用。ngDoCheck
: 在每个变更检测周期中调用。ngAfterContentInit
: 在 Angular 完成组件内容投影之后调用。ngAfterContentChecked
: 在每个变更检测周期之后调用,用于检查内容投影。ngAfterViewInit
: 在 Angular 初始化组件视图及其子视图之后调用。ngAfterViewChecked
: 在每个变更检测周期之后调用,用于检查组件视图及其子视图。ngOnDestroy
: 在 Angular 销毁组件或指令之前调用。
6. 组件通信 (Component Communication)
父子组件通信
父组件通过 [ ]
自定义属性传值,子组件通过 @Input
装饰器接收。
typescript
// 父组件
<app-child [data]="parentData"></app-child>
// 子组件
@Input() data: string;
子父组件通信
子组件通过 @Output
和 EventEmitter
向父组件发送数据。
typescript
// 子组件
@Output() dataEvent = new EventEmitter<string>();
this.dataEvent.emit('some data');
// 父组件
<app-child (dataEvent)="handleData($event)"></app-child>
同模块组件通信
通过服务进行通信。
typescript
constructor(private serviceName: ServiceName)
状态管理库 (NgRx)
使用 NgRx 进行复杂的状态管理。
7. 模板 (Templates)
模板引用变量
使用 #
定义模板引用变量,允许你在模板中引用元素或组件实例。
html
<input #inputElement type="text">
结构指令
使用 *
语法,如 *ngIf
, *ngFor
等,添加或移除 DOM 元素。
html
<div [ngSwitch]="viewMode">
<p *ngSwitchCase="'map'">Map View</p>
</div>
事件绑定
使用 ()
语法绑定事件。
属性绑定
使用 []
语法绑定属性。
双向绑定
使用 [()]
语法实现双向绑定。
8. 自定义指令 (Custom Directives)
属性指令
typescript
import { Directive, ElementRef, Renderer2, HostListener } from '@angular/core';
@Directive({
selector: '[myDirective]'
})
export class HighlightDirective {
constructor(private el: ElementRef, private renderer: Renderer2) {}
@HostListener('mouseenter') onMouseEnter() {
this.highlight('yellow');
}
private highlight(color: string) {
this.renderer.setStyle(this.el.nativeElement, 'backgroundColor', color);
}
}
结构指令
typescript
import { Directive, TemplateRef, ViewContainerRef, Input } from '@angular/core';
@Directive({
selector: '[appUnless]'
})
export class UnlessDirective {
private hasView = false;
constructor(private templateRef: TemplateRef<any>, private viewContainer: ViewContainerRef) {}
@Input() set appUnless(condition: boolean) {
if (!condition && !this.hasView) {
this.viewContainer.createEmbeddedView(this.templateRef);
this.hasView = true;
} else if (condition && this.hasView) {
this.viewContainer.clear();
this.hasView = false;
}
}
}
9. 服务 (Services)
使用 Angular CLI 创建服务,并使用 @Injectable
装饰器定义服务。
bash
ng generate service data
typescript
@Injectable({
providedIn: 'root'
})
export class DataService {
// 服务代码
}
10. HTTP 客户端 (HTTP Client)
使用 HttpClient
服务进行 HTTP 请求。
typescript
import { HttpClient } from '@angular/common/http';
constructor(private http: HttpClient) {}
this.http.get('url').subscribe(data => {
console.log(data);
});
拦截器 (Interceptors)
typescript
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http';
import { Observable } from 'rxjs';
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const authToken = 'your-auth-token';
const authReq = req.clone({
setHeaders: {
Authorization: `Bearer ${authToken}`
}
});
return next.handle(authReq);
}
}
11. 路由 (Routing)
配置路由
在应用程序的根模块中导入 RouterModule
并配置路由。
typescript
import { RouterModule, Routes } from '@angular/router';
const routes: Routes = [
{ path: '', component: HomeComponent },
{ path: 'about', component: AboutComponent }
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule {}
路由守卫 (Guards)
创建路由守卫并在路由配置中使用 canActivate
属性来保护路由。
typescript
import { CanActivate } from '@angular/router';
@Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivate {
canActivate(): boolean {
return true; // Replace with actual authentication check
}
}
路由参数和查询参数
使用 ActivatedRoute
服务来访问路由参数和查询参数。
typescript
import { ActivatedRoute } from '@angular/router';
constructor(private route: ActivatedRoute) {}
ngOnInit() {
this.route.paramMap.subscribe(params => {
console.log(params.get('id'));
});
this.route.queryParamMap.subscribe(params => {
console.log(params.get('queryParam'));
});
}
懒加载模块
使用 NgModule
定义懒加载模块,并在路由配置中使用 loadChildren
属性来按需加载模块。
typescript
const routes: Routes = [
{ path: 'lazy', loadChildren: () => import('./lazy/lazy.module').then(m => m.LazyModule) }
];
12. 表单 (Forms)
模板驱动表单
使用 FormsModule
处理模板驱动表单。
typescript
import { FormsModule } from '@angular/forms';
@NgModule({
imports: [FormsModule]
})
export class AppModule {}
html
<form #form="ngForm" (ngSubmit)="onSubmit(form)">
<input name="name" ngModel required>
<button type="submit">Submit</button>
</form>
响应式表单
使用 ReactiveFormsModule
处理响应式表单。
typescript
import { ReactiveFormsModule } from '@angular/forms';
@NgModule({
imports: [ReactiveFormsModule]
})
export class AppModule {}
typescript
import { FormGroup, FormControl, Validators } from '@angular/forms';
this.form = new FormGroup({
name: new FormControl('', Validators.required)
});
html
<form [formGroup]="form" (ngSubmit)="onSubmit()">
<input formControlName="name">
<button type="submit">Submit</button>
</form>
表单验证
使用内置验证器和自定义验证器进行表单验证。
typescript
import { AbstractControl, ValidatorFn } from '@angular/forms';
export function forbiddenNameValidator(nameRe: RegExp): ValidatorFn {
return (control: AbstractControl): { [key: string]: any } | null => {
const forbidden = nameRe.test(control.value);
return forbidden ? { 'forbiddenName': { value: control.value } } : null;
};
}
13. TypeScript 高级特性
元组 (Tuple)
元组是一种不可变的数据结构,用于存储一组有序的元素。
typescript
let tuple: [number, string] = [1, 'hello'];
条件类型
条件类型根据条件返回不同的类型。
typescript
type IsString<T> = T extends string ? true : false;
映射类型
映射类型允许你创建一个新类型,该类型基于另一个类型的所有属性。
typescript
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
内置实用类型
Partial<T>
: 将类型T
的所有属性变为可选。Required<T>
: 将类型T
的所有属性变为必填。Readonly<T>
: 将类型T
的所有属性变为只读。Pick<T, K>
: 从类型T
中选择一组属性K
,并创建一个新的类型。Omit<T, K>
: 从类型T
中排除一组属性K
。Record<K, T>
: 将键类型K
映射到值类型T
。Exclude<T, U>
: 从类型T
中排除所有可以赋值给类型U
的属性。Extract<T, U>
: 从类型T
中提取所有可以赋值给类型U
的属性。NonNullable<T>
: 从类型T
中排除null
和undefined
。ReturnType<T>
: 获取函数类型T
的返回类型。InstanceType<T>
: 获取构造函数类型T
的实例类型。
通过理解和掌握这些 Angular 开发中的核心概念和常用技术,你将能够构建强大和灵活的 Angular 应用程序。如果你有任何问题或需要进一步的帮助,请随时提问!
希望这篇文章对你有所帮助!如果你有任何问题或需要进一步的帮助,请随时提问!