赞
踩
Angular 是一个由 Google 维护的开源前端框架。它最早在 2010 年发布,最初版本称为 AngularJS。2016 年,团队发布了一个完全重写的版本,称为 Angular 2,之后的版本(如 Angular 4、Angular 5 等)都统称为 Angular。
Angular 使用 TypeScript 编写,提供了静态类型检查、现代 JavaScript 特性等优点,有助于提高代码质量和开发效率。
采用组件式开发,将应用程序分割成独立的、可复用的组件,每个组件包含自己的模板、样式和逻辑。
使用 NgModule 来组织代码,一个 NgModule 可以包含组件、指令、管道和服务等,提供了良好的模块化支持。
Angular 提供了强大的依赖注入机制,简化了服务的创建和管理,提高了代码的可测试性和可维护性。
Angular 使用直观的模板语法来定义组件的视图,支持数据绑定、指令和事件绑定等。
Angular 内置强大的路由模块,可以轻松地定义应用程序的导航和页面切换。
提供了两种表单处理方式:模板驱动表单和响应式表单,满足不同需求。
Angular 大量使用 RxJS(Reactive Extensions for JavaScript)来处理异步数据流,非常适合复杂的数据交互场景。
由于 Angular 涉及的概念较多(如依赖注入、RxJS、TypeScript 等),学习曲线相对较陡。
理解和应用 Angular 的变更检测机制和 Zone.js 是性能优化的关键,需要一定的深入学习。
随着项目规模的扩大,如何有效地管理模块、组件、服务等也是一个挑战。
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'my-angular-app';
}
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { AppComponent } from './app.component'; @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
{{ expression }}
[property]="expression"
(event)="handler"
[(ngModel)]="property"
*ngIf
, *ngFor
[ngClass]
, [ngStyle]
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root',
})
export class DataService {
getData() {
return ['data1', 'data2', 'data3'];
}
}
import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { HomeComponent } from './home/home.component'; import { AboutComponent }```typescript import { AboutComponent } from './about/about.component'; const routes: Routes = [ { path: '', component: HomeComponent }, { path: 'about', component: AboutComponent } ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule { }
<form #form="ngForm" (ngSubmit)="onSubmit(form)">
<input type="text" name="username" ngModel required>
<button type="submit">Submit</button>
</form>
import { Component, OnInit } from '@angular/core'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; @Component({ selector: 'app-form', templateUrl: './form.component.html' }) export class FormComponent implements OnInit { form: FormGroup; constructor(private fb: FormBuilder) { } ngOnInit() { this.form = this.fb.group({ username: ['', Validators.required] }); } onSubmit() { console.log(this.form.value); } }
<form [formGroup]="form" (ngSubmit)="onSubmit()">
<input formControlName="username">
<button type="submit">Submit</button>
</form>
Angular 使用 Zone.js 来捕获异步操作,然后触发变更检测机制来更新视图。变更检测机制的核心是脏值检测策略,Angular 会对比数据的当前值和之前的值,决定是否重新渲染视图。
Angular 的依赖注入机制基于提供者(Provider)和注入器(Injector)。每个服务、组件等都可以声明依赖项,Angular 会根据依赖关系图自动注入所需的依赖。
Angular 的编译过程分为 AOT(Ahead-of-Time)和 JIT(Just-in-Time)两种模式:
Angular 使用虚拟 DOM 进行渲染优化,类似于 React。通过虚拟 DOM,Angular 可以高效地计算出需要更新的部分,减少直接操作真实 DOM 的次数,从而提高性能。
Angular 的模块系统通过 NgModule 实现。每个 NgModule 都有自己的执行环境,可以包含组件、指令、管道和服务等。模块化设计有助于代码分离和按需加载,提高了应用的可维护性和性能。
Angular 是一个功能强大且全面的前端框架,适用于大规模、复杂的 Web 应用开发。它采用 TypeScript 进行开发,提供了丰富的工具和功能(如依赖注入、变更检测、模块化、路由等),尽管学习曲线较陡,但在大型项目中表现出色。掌握 Angular 的核心概念和原理,能够帮助开发者构建高性能、高可维护性的 Web 应用。
当然,下面是关于 Angular 的更多详细信息,包括一些高级特性、最佳实践以及常见的开发模式。
懒加载是 Angular 中提高性能的重要特性。通过懒加载,可以按需加载模块而不是在应用启动时加载所有模块。
const routes: Routes = [
{ path: 'home', component: HomeComponent },
{ path: 'about', loadChildren: () => import('./about/about.module').then(m => m.AboutModule) }
];
Angular CLI 是一个强大的命令行工具,用于初始化、开发、构建和维护 Angular 应用程序。
# 安装 Angular CLI
npm install -g @angular/cli
# 创建新项目
ng new my-angular-app
# 启动开发服务器
ng serve
# 生成组件、服务等
ng generate component my-component
Angular 提供了内置的国际化支持,可以轻松地将应用程序本地化到多种语言。
import { registerLocaleData } from '@angular/common';
import localeFr from '@angular/common/locales/fr';
registerLocaleData(localeFr, 'fr');
在运行时动态加载和渲染组件是 Angular 的一个高级特性,适用于需要根据用户交互动态生成内容的场景。
import { Component, ComponentFactoryResolver, ViewChild, ViewContainerRef } from '@angular/core'; @Component({ selector: 'app-dynamic-loader', template: `<ng-container #container></ng-container>` }) export class DynamicLoaderComponent { @ViewChild('container', { read: ViewContainerRef, static: true }) container: ViewContainerRef; constructor(private resolver: ComponentFactoryResolver) { } loadComponent(component: any) { const factory = this.resolver.resolveComponentFactory(component); this.container.clear(); this.container.createComponent(factory); } }
使用 Angular Universal 可以实现服务端渲染,从而提高应用的 SEO 和首屏加载速度。
# 安装 Angular Universal
ng add @nguniversal/express-engine
# 构建和运行 SSR 应用
npm run build:ssr
npm run serve:ssr
OnPush
变更检测策略,减少不必要的视图更新。async
管道、Promise
和 Observable
。// 智能组件 @Component({ selector: 'app-smart', template: `<app-dumb [data]="data" (event)="handleEvent($event)"></app-dumb>` }) export class SmartComponent { data = this.dataService.getData(); constructor(private dataService: DataService) { } handleEvent(event: any) { /* 处理事件 */ } } // 哑组件 @Component({ selector: 'app-dumb', template: `<div *ngFor="let item of data">{{ item }}</div>` }) export class DumbComponent { @Input() data: any[]; @Output() event = new EventEmitter<any>(); }
对于复杂的应用,可以采用状态管理库(如 NgRx)来管理应用状态当然,接下来我会详细介绍 Angular 的状态管理、单元测试、与其他技术的集成,以及一些高级调试技巧。
NgRx 是 Angular 中常用的状态管理库,基于 Redux 架构,提供了单一状态树、不可变状态、纯函数 reducer 等特点。
ng add @ngrx/store
ng add @ngrx/effects
定义状态接口和初始状态:
// state.ts
export interface AppState {
count: number;
}
export const initialState: AppState = {
count: 0,
};
定义 actions:
// actions.ts
import { createAction, props } from '@ngrx/store';
export const increment = createAction('[Counter] Increment');
export const decrement = createAction('[Counter] Decrement');
export const reset = createAction('[Counter] Reset', props<{ count: number }>());
定义 reducer:
// reducer.ts
import { createReducer, on } from '@ngrx/store';
import { increment, decrement, reset } from './actions';
import { AppState, initialState } from './state';
const _counterReducer = createReducer(
initialState,
on(increment, state => ({ ...state, count: state.count + 1 })),
on(decrement, state => ({ ...state, count: state.count - 1 })),
on(reset, (state, { count }) => ({ ...state, count }))
);
export function counterReducer(state: AppState | undefined, action: Action) {
return _counterReducer(state, action);
}
在应用模块中引入 Store 模块:
import { StoreModule } from '@ngrx/store';
import { counterReducer } from './reducer';
@NgModule({
imports: [
StoreModule.forRoot({ count: counterReducer }),
],
})
export class AppModule { }
在组件中使用 Store:
import { Component } from '@angular/core'; import { Store } from '@ngrx/store'; import { AppState } from './state'; import { increment, decrement, reset } from './actions'; @Component({ selector: 'app-counter', template: ` <div>Count: {{ count$ | async }}</div> <button (click)="increment()">Increment</button> <button (click)="decrement()">Decrement</button> <button (click)="reset(0)">Reset</button> ` }) export class CounterComponent { count$ = this.store.select(state => state.count); constructor(private store: Store<AppState>) {} increment() { this.store.dispatch(increment()); } decrement() { this.store.dispatch(decrement()); } reset(value: number) { this.store.dispatch(reset({ count: value })); } }
Akita 是另一种用于 Angular 的状态管理库,提供了灵活的状态管理方式,适合大型应用。
ng add @datorama/akita
import { Store, StoreConfig } from '@datorama/akita'; export interface AppState { count: number; } export function createInitialState(): AppState { return { count: 0, }; } @StoreConfig({ name: 'app' }) export class AppStore extends Store<AppState> { constructor() { super(createInitialState()); } }
import { Component } from '@angular/core'; import { AppStore } from './app.store'; @Component({ selector: 'app-counter', template: ` <div>Count: {{ count$ | async }}</div> <button (click)="increment()">Increment</button> <button (click)="decrement()">Decrement</button> <button (click)="reset()">Reset</button> ` }) export class CounterComponent { count$ = this.appStore.select(state => state.count); constructor(private appStore: AppStore) {} increment() { this.appStore.update(state => ({ count: state.count + 1 })); } decrement() { this.appStore.update(state => ({ count: state.count - 1 })); } reset() { this.appStore.reset(); } }
Angular 提供了强大的单元测试支持,使用 Karma 和 Jasmine 进行测试。
Angular CLI 自动生成的项目已经配置好了 Karma 和 Jasmine,无需额外配置。
使用 TestBed 创建组件并进行测试:
import { ComponentFixture, TestBed } from '@angular/core/testing'; import { CounterComponent } from './counter.component'; describe('CounterComponent', () => { let component: CounterComponent; let fixture: ComponentFixture<CounterComponent>; beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [ CounterComponent ] }) .compileComponents(); }); beforeEach(() => { fixture = TestBed.createComponent(CounterComponent); component = fixture.componentInstance; fixture.detectChanges(); }); it('should create', () => { expect(component).toBeTruthy(); }); it('should increment count', () => { component.increment(); expect(component.count).toBe(1); }); it('should decrement count', () => { component.decrement(); expect(component.count).toBe(-1); }); it('should reset count', () => { component.reset(0); expect(component.count).toBe(0); }); });
测试服务时,使用 TestBed 配置提供者:
import { TestBed } from '@angular/core/testing'; import { DataService } from './data.service'; describe('DataService', () => { let service: DataService; beforeEach(() => { TestBed.configureTestingModule({}); service = TestBed.inject(DataService); }); it('should be created', () => { expect(service).toBeTruthy(); }); it('should get data', () => { const data = service.getData(); expect(data).toEqual(['item1', 'item2']); }); });
使用 Angular CLI 运行测试:
ng test
使用 Angular 的 HttpClient 模块来与后端 API 进行通信。
import { HttpClientModule } from '@angular/common/http';
@NgModule({
imports: [ HttpClientModule ],
})
export class AppModule { }
import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; @Injectable({ providedIn: 'root', }) export class ApiService { constructor(private http: HttpClient) {} getData(): Observable<any> { return this.http.get('https://api.example.com/data'); } postData(data: any): Observable<any> { return this.http.post('https://api.example.com/data', data); } }
import { Component, OnInit } from '@angular/core'; import { ApiService } from './api.service'; @Component({ selector: 'app-data', template: `<div *ngFor="let item of data">{{ item }}</div>`, }) export class DataComponent implements OnInit { data: any; constructor(private apiService: ApiService) {} ngOnInit() { this.apiService.getData().subscribe(data => this.data = data); } }
Angular 可以轻松集成第三方库,如 RxJS、Lodash 等。
import { of } from 'rxjs';
import { map } from 'rxjs/operators';
const observable = of(1, 2, 3).pipe(
map(x => x * 2)
);
observable.subscribe(value => console.log(value)); // 输出 2, 4, 6
import * as _ from 'lodash';
const array = [1, 2, 3, 4];
const doubled = _.map(array, x => x * 2);
console.log(doubled); // 输出 [2, 4, 6, 8]
当然,我将继续介绍更多关于 Angular 的内容,包括高级调试技巧、动画、表单处理、以及一些常见的开发工具和资源。
在开发过程中,可以启用 Angular 的 Debug 模式,以便在控制台中查看详细的调试信息。
import { enableProdMode } from '@angular/core';
if (environment.production) {
enableProdMode();
} else {
// 开发模式下启用调试信息
import('zone.js/plugins/zone-error'); // Included with Angular CLI.
}
ng.probe
在浏览器控制台中,可以使用 ng.probe
方法来访问组件实例和调试信息。
// 获取组件实例
const component = ng.probe(document.querySelector('app-root')).componentInstance;
console.log(component);
Augury
Augury 是一个用于调试 Angular 应用的 Chrome 扩展,提供组件树、依赖注入、路由等信息的可视化展示。
Angular 提供了强大的动画支持,通过 Angular Animations 模块可以实现复杂的动画效果。
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
@NgModule({
imports: [BrowserAnimationsModule],
})
export class AppModule {}
使用 trigger
、state
、style
、transition
和 animate
来定义动画。
import { trigger, state, style, transition, animate } from '@angular/animations'; @Component({ selector: 'app-animated', template: ` <div [@fadeInOut]="'in'">Fade In Out Animation</div> <button (click)="toggleState()">Toggle State</button> `, animations: [ trigger('fadeInOut', [ state('in', style({ opacity: 1 })), transition(':enter', [ style({ opacity: 0 }), animate(600) ]), transition(':leave', [ animate(600, style({ opacity: 0 })) ]) ]) ] }) export class AnimatedComponent { state = 'in'; toggleState() { this.state = this.state === 'in' ? 'out' : 'in'; } }
Angular 提供了两种表单处理方式:模板驱动表单和响应式表单。
模板驱动表单使用 Angular 的指令和模板语法来处理表单。
import { FormsModule } from '@angular/forms';
@NgModule({
imports: [FormsModule],
})
export class AppModule {}
<!-- template-driven-form.component.html -->
<form #form="ngForm" (ngSubmit)="onSubmit(form)">
<label for="name">Name:</label>
<input type="text" id="name" name="name" ngModel>
<button type="submit">Submit</button>
</form>
// template-driven-form.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-template-driven-form',
templateUrl: './template-driven-form.component.html'
})
export class TemplateDrivenFormComponent {
onSubmit(form: any) {
console.log('Form Data:', form.value);
}
}
响应式表单使用 FormBuilder
和 FormGroup
来处理表单。
import { ReactiveFormsModule, FormBuilder, FormGroup } from '@angular/forms';
@NgModule({
imports: [ReactiveFormsModule],
})
export class AppModule {}
<!-- reactive-form.component.html -->
<form [formGroup]="form" (ngSubmit)="onSubmit()">
<label for="name">Name:</label>
<input type="text" id="name" formControlName="name">
<button type="submit">Submit</button>
</form>
// reactive-form.component.ts import { Component, OnInit } from '@angular/core'; import { FormBuilder, FormGroup } from '@angular/forms'; @Component({ selector: 'app-reactive-form', templateUrl: './react ### 2. **响应式表单** 响应式表单使用 `FormBuilder` 和 `FormGroup` 来处理表单。 #### 创建表单 ```typescript import { Component, OnInit } from '@angular/core'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; @Component({ selector: 'app-reactive-form', templateUrl: './reactive-form.component.html' }) export class ReactiveFormComponent implements OnInit { form: FormGroup; constructor(private fb: FormBuilder) {} ngOnInit() { this.form = this.fb.group({ name: ['', Validators.required], email: ['', [Validators.required, Validators.email]], password: ['', [Validators.required, Validators.minLength(6)]] }); } onSubmit() { if (this.form.valid) { console.log('Form Data:', this.form.value); } else { console.log('Form is invalid'); } } }
<form [formGroup]="form" (ngSubmit)="onSubmit()"> <div> <label for="name">Name:</label> <input type="text" id="name" formControlName="name"> <div *ngIf="form.get('name').invalid && form.get('name').touched"> Name is required </div> </div> <div> <label for="email">Email:</label> <input type="email" id="email" formControlName="email"> <div *ngIf="form.get('email').invalid && form.get('email').touched"> Enter a valid email </div> </div> <div> <label for="password">Password:</label> <input type="password" id="password" formControlName="password"> <div *ngIf="form.get('password').invalid && form.get('password').touched"> Password must be at least 6 characters long </div> </div> <button type="submit">Submit</button> </form>
Angular 的路由模块允许你在应用中定义导航路径。
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { AboutComponent } from './about/about.component';
const routes: Routes = [
{ path: '', component: HomeComponent },
{ path: 'about', component: AboutComponent }
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
<nav>
<a routerLink="/">Home</a>
<a routerLink="/about">About</a>
</nav>
<router-outlet></router-outlet>
路由守卫用于保护路由,确保用户具有访问权限。
import { Injectable } from '@angular/core'; import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router'; import { AuthService } from './auth.service'; @Injectable({ providedIn: 'root' }) export class AuthGuard implements CanActivate { constructor(private authService: AuthService, private router: Router) {} canActivate( next: ActivatedRouteSnapshot, state: RouterStateSnapshot ): boolean { if (this.authService.isLoggedIn()) { return true; } else { this.router.navigate(['/login']); return false; } } }
const routes: Routes = [
{ path: '', component: HomeComponent },
{ path: 'about', component: AboutComponent, canActivate: [AuthGuard] }
];
Angular 提供了内置的国际化支持,用于多语言应用程序。
创建翻译文件 messages.xlf
:
<?xml version="1.0" encoding="UTF-8" ?> <xliff version="1.2"> <file source-language="en" datatype="plaintext" original="ng2.template"> <body> <trans-unit id="homeTitle" datatype="html"> <source>Home</source> <target>Accueil</target> </当然,我将继续介绍更多关于 Angular 的内容,包括国际化的详细步骤、服务端渲染、以及一些常用的开发工具和资源。 ## 十七、国际化(继续) ### 1. **准备翻译文件** 创建翻译文件 `messages.xlf`: ```xml <?xml version="1.0" encoding="UTF-8" ?> <xliff version="1.2"> <file source-language="en" datatype="plaintext" original="ng2.template"> <body> <trans-unit id="homeTitle" datatype="html"> <source>Home</source> <target>Accueil</target> </trans-unit> <trans-unit id="aboutTitle" datatype="html"> <source>About</source> <target>À propos</target> </trans-unit> </body> </file> </xliff>
在 angular.json
中添加国际化配置:
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"projects": {
"your-project-name": {
"i18n": {
"sourceLocale": "en",
"locales": {
"fr": "src/locale/messages.fr.xlf"
}
},
...
}
}
}
使用 Angular 内置的 i18n
属性标记可翻译的文本:
<h1 i18n="homeTitle">Home</h1>
<p i18n="aboutTitle">About</p>
使用 Angular CLI 构建多语言版本:
ng build --localize
Angular Universal 是一个用于实现 Angular 应用服务端渲染的库。
ng add @nguniversal/express-engine
更新 app.server.module.ts
以适配服务端渲染:
import { NgModule } from '@angular/core';
import { ServerModule } from '@angular/platform-server';
import { AppModule } from './app.module';
import { AppComponent } from './app.component';
@NgModule({
imports: [
AppModule,
ServerModule
],
bootstrap: [AppComponent]
})
export class AppServerModule {}
配置 server.ts
文件以启动 Express 服务器:
import 'zone.js/node'; import { ngExpressEngine } from '@nguniversal/express-engine'; import * as express from 'express'; import { join } from 'path'; import { APP_BASE_HREF } from '@angular/common'; import { existsSync } from 'fs'; import { AppServerModule } from './src/main.server'; // The Express app is exported so that it can be used by serverless Functions. export function app(): express.Express { const server = express(); const distFolder = join(process.cwd(), 'dist/your-project-name/browser'); const indexHtml = existsSync(join(distFolder, 'index.original.html')) ? 'index.original.html' : 'index'; server.engine('html', ngExpressEngine({ bootstrap: AppServerModule, })); server.set('view engine', 'html'); server.set('views', distFolder); // Serve static files from /browser server.get('*.*', express.static(distFolder, { maxAge: '1y' })); // All regular routes use the Universal engine server.get('*', (req, res) => { res.render(indexHtml, { req, providers: [{ provide: APP_BASE_HREF, useValue: req.baseUrl }] }); }); return server; } function run(): void { const port = process.env.PORT || 4000; // Start up the Node server const server = app(); server.listen(port, () => { console.log(`Node Express server listening on http://localhost:${port}`); }); } // Webpack will replace 'require' with '__webpack_require__' // '__non_webpack_require__' is a proxy to Node 'require' declare const __non_webpack_require__: NodeRequire; const mainModule = __non_webpack_require__.main; const moduleFilename = mainModule && mainModule.filename || ''; if (moduleFilename === __filename || moduleFilename.includes('iisnode')) { run(); } export * from './src/main.server';
使用 Angular CLI 构建和运行 SSR 应用:
npm run build:ssr
npm run serve:ssr
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。