【Angular主要内容归纳】

@Angular主要内容归纳

Angular 完整教程 - 核心内容详解

目录

  1. 组件 (Components)
  2. 模块 (Modules)
  3. 服务 (Services)
  4. 依赖注入 (Dependency Injection)
  5. 路由 (Routing)
  6. 数据绑定 (Data Binding)
  7. 指令 (Directives)
  8. 管道 (Pipes)
  9. HTTP 客户端
  10. 表单 (Forms)
  11. 生命周期钩子 (Lifecycle Hooks)
  12. RxJS 和 Observable
  13. 状态管理
  14. 测试

1. 组件 (Components)

组件是 Angular 应用的基本构建块,每个组件包含:

  • 模板 (Template): HTML 视图
  • 类 (Class): 组件逻辑和属性
  • 样式 (Styles): CSS/SCSS 样式
  • 元数据 (Metadata): @Component 装饰器

示例:基础组件

// app.component.tsimport{ Component }from'@angular/core';@Component({ selector:'app-root', templateUrl:'./app.component.html', styleUrls:['./app.component.css']})exportclassAppComponent{ title ='我的 Angular 应用'; count =0;increment(){this.count++;}decrement(){this.count--;}}
<!-- app.component.html --><divclass="container"><h1>{{ title }}</h1><p>计数器: {{ count }}</p><button(click)="increment()">增加</button><button(click)="decrement()">减少</button></div>

示例:带输入输出的组件

// user-card.component.tsimport{ Component, Input, Output, EventEmitter }from'@angular/core';@Component({ selector:'app-user-card', template:` <div> <h3>{{ user.name }}</h3> <p>邮箱: {{ user.email }}</p> <button (click)="onSelect()">选择用户</button> </div> `})exportclassUserCardComponent{@Input() user!:{ name:string; email:string};@Output() userSelected =newEventEmitter<string>();onSelect(){this.userSelected.emit(this.user.email);}}
// parent.component.ts@Component({ selector:'app-parent', template:` <app-user-card [user]="currentUser" (userSelected)="handleUserSelection($event)"> </app-user-card> `})exportclassParentComponent{ currentUser ={ name:'张三', email:'[email protected]'};handleUserSelection(email:string){console.log('选中的用户邮箱:', email);}}

2. 模块 (Modules)

模块用于组织应用代码,NgModule 是 Angular 的模块系统。

示例:根模块

// app.module.tsimport{ NgModule }from'@angular/core';import{ BrowserModule }from'@angular/platform-browser';import{ FormsModule }from'@angular/forms';import{ HttpClientModule }from'@angular/common/http';import{ AppComponent }from'./app.component';import{ UserCardComponent }from'./user-card.component';import{ UserService }from'./user.service';@NgModule({ declarations:[ AppComponent, UserCardComponent ], imports:[ BrowserModule, FormsModule, HttpClientModule ], providers:[ UserService ], bootstrap:[AppComponent]})exportclassAppModule{}

示例:功能模块

// user.module.tsimport{ NgModule }from'@angular/core';import{ CommonModule }from'@angular/common';import{ UserListComponent }from'./user-list.component';import{ UserDetailComponent }from'./user-detail.component';import{ UserService }from'./user.service';@NgModule({ declarations:[ UserListComponent, UserDetailComponent ], imports:[ CommonModule ], providers:[ UserService ], exports:[ UserListComponent ]})exportclassUserModule{}

3. 服务 (Services)

服务用于封装业务逻辑、数据访问和共享功能。

示例:基础服务

// user.service.tsimport{ Injectable }from'@angular/core';import{ HttpClient }from'@angular/common/http';import{ Observable }from'rxjs';exportinterfaceUser{ id:number; name:string; email:string;}@Injectable({ providedIn:'root'// 根级别注入,单例模式})exportclassUserService{private apiUrl ='https://api.example.com/users';constructor(private http: HttpClient){}getUsers(): Observable<User[]>{returnthis.http.get<User[]>(this.apiUrl);}getUserById(id:number): Observable<User>{returnthis.http.get<User>(`${this.apiUrl}/${id}`);}createUser(user: User): Observable<User>{returnthis.http.post<User>(this.apiUrl, user);}updateUser(id:number, user: Partial<User>): Observable<User>{returnthis.http.put<User>(`${this.apiUrl}/${id}`, user);}deleteUser(id:number): Observable<void>{returnthis.http.delete<void>(`${this.apiUrl}/${id}`);}}

示例:带缓存的服务

// product.service.tsimport{ Injectable }from'@angular/core';import{ BehaviorSubject, Observable }from'rxjs';import{ tap }from'rxjs/operators';@Injectable({ providedIn:'root'})exportclassProductService{private productsSubject =newBehaviorSubject<any[]>([]);public products$ =this.productsSubject.asObservable();constructor(private http: HttpClient){this.loadProducts();}privateloadProducts(){this.http.get<any[]>('/api/products').pipe(tap(products =>this.productsSubject.next(products))).subscribe();}getProducts(): Observable<any[]>{returnthis.products$;}addProduct(product:any){const current =this.productsSubject.value;this.productsSubject.next([...current, product]);}}

4. 依赖注入 (Dependency Injection)

Angular 的依赖注入系统自动管理依赖关系。

示例:构造函数注入

// component.tsimport{ Component }from'@angular/core';import{ UserService }from'./user.service';@Component({ selector:'app-user-list', template:'<div>用户列表</div>'})exportclassUserListComponent{constructor(private userService: UserService){// Angular 自动注入 UserService}ngOnInit(){this.userService.getUsers().subscribe(users =>{console.log(users);});}}

示例:可选依赖和注入令牌

// logger.service.tsimport{ Injectable, InjectionToken, Optional, Inject }from'@angular/core';exportconstLOG_LEVEL=newInjectionToken<string>('LOG_LEVEL');@Injectable({ providedIn:'root'})exportclassLoggerService{constructor(@Optional()@Inject(LOG_LEVEL)private logLevel:string='INFO'){console.log('日志级别:',this.logLevel);}log(message:string){console.log(`[${this.logLevel}] ${message}`);}}
// app.module.ts providers:[{ provide:LOG_LEVEL, useValue:'DEBUG'}]

5. 路由 (Routing)

Angular Router 用于实现单页应用的路由导航。

示例:基础路由配置

// app-routing.module.tsimport{ NgModule }from'@angular/core';import{ RouterModule, Routes }from'@angular/router';import{ HomeComponent }from'./home/home.component';import{ UserListComponent }from'./user/user-list.component';import{ UserDetailComponent }from'./user/user-detail.component';import{ NotFoundComponent }from'./not-found/not-found.component';const routes: Routes =[{ path:'', redirectTo:'/home', pathMatch:'full'},{ path:'home', component: HomeComponent },{ path:'users', component: UserListComponent },{ path:'users/:id', component: UserDetailComponent },{ path:'**', component: NotFoundComponent }];@NgModule({ imports:[RouterModule.forRoot(routes)], exports:[RouterModule]})exportclassAppRoutingModule{}

示例:路由守卫

// auth.guard.tsimport{ Injectable }from'@angular/core';import{ CanActivate, Router }from'@angular/router';import{ AuthService }from'./auth.service';@Injectable({ providedIn:'root'})exportclassAuthGuardimplementsCanActivate{constructor(private authService: AuthService,private router: Router ){}canActivate():boolean{if(this.authService.isAuthenticated()){returntrue;}else{this.router.navigate(['/login']);returnfalse;}}}
// 在路由中使用守卫const routes: Routes =[{ path:'dashboard', component: DashboardComponent, canActivate:[AuthGuard]}];

示例:路由参数和查询参数

// user-detail.component.tsimport{ Component, OnInit }from'@angular/core';import{ ActivatedRoute, Router }from'@angular/router';@Component({ selector:'app-user-detail', template:` <div> <h2>用户详情</h2> <p>ID: {{ userId }}</p> <p>模式: {{ mode }}</p> <button (click)="goBack()">返回</button> </div> `})exportclassUserDetailComponentimplementsOnInit{ userId!:number; mode!:string;constructor(private route: ActivatedRoute,private router: Router ){}ngOnInit(){// 获取路由参数this.userId =+this.route.snapshot.paramMap.get('id')!;// 获取查询参数this.mode =this.route.snapshot.queryParamMap.get('mode')||'view';// 监听参数变化this.route.paramMap.subscribe(params =>{this.userId =+params.get('id')!;});}goBack(){this.router.navigate(['/users']);}}

6. 数据绑定 (Data Binding)

Angular 支持多种数据绑定方式。

示例:插值绑定

<!-- 显示组件属性 --><h1>{{ title }}</h1><p>当前时间: {{ getCurrentTime() }}</p>

示例:属性绑定

<!-- 绑定 HTML 属性 --><img[src]="imageUrl"[alt]="imageAlt"><!-- 绑定 DOM 属性 --><button[disabled]="isDisabled">提交</button><!-- 绑定类 --><div[class.active]="isActive"[class.error]="hasError"></div><!-- 绑定样式 --><div[style.color]="textColor"[style.font-size.px]="fontSize"></div>

示例:事件绑定

<!-- 点击事件 --><button(click)="handleClick()">点击</button><!-- 带事件对象 --><button(click)="handleClick($event)">点击</button><!-- 输入事件 --><input(input)="onInput($event)"(keyup.enter)="onEnter()">

示例:双向绑定

// component.tsexportclassFormComponent{ username =''; email ='';}
<!-- 使用 ngModel 双向绑定 --><input[(ngModel)]="username"placeholder="用户名"><input[(ngModel)]="email"type="email"placeholder="邮箱"><!-- 等价写法 --><input[ngModel]="username"(ngModelChange)="username = $event">

7. 指令 (Directives)

指令用于扩展 HTML 元素的功能。

示例:结构型指令

<!-- *ngIf - 条件渲染 --><div*ngIf="isLoggedIn">欢迎回来!</div><div*ngIf="!isLoggedIn">请登录</div><!-- *ngFor - 列表渲染 --><ul><li*ngFor="let user of users; let i = index; let first = first"> {{ i + 1 }}. {{ user.name }} <span*ngIf="first">(第一个)</span></li></ul><!-- *ngSwitch - 多条件判断 --><div[ngSwitch]="status"><p*ngSwitchCase="'loading'">加载中...</p><p*ngSwitchCase="'success'">成功!</p><p*ngSwitchCase="'error'">错误!</p><p*ngSwitchDefault>未知状态</p></div>

示例:属性型指令

// highlight.directive.tsimport{ Directive, ElementRef, Input, Renderer2, OnInit }from'@angular/core';@Directive({ selector:'[appHighlight]'})exportclassHighlightDirectiveimplementsOnInit{@Input() appHighlight ='yellow';@Input() defaultColor ='transparent';constructor(private el: ElementRef,private renderer: Renderer2 ){}ngOnInit(){this.setBackgroundColor(this.appHighlight ||this.defaultColor);}privatesetBackgroundColor(color:string){this.renderer.setStyle(this.el.nativeElement,'background-color', color);}}
<!-- 使用自定义指令 --><pappHighlight="yellow">高亮文本</p><p[appHighlight]="highlightColor">动态高亮</p>

示例:结构型指令(自定义)

// unless.directive.tsimport{ Directive, Input, TemplateRef, ViewContainerRef }from'@angular/core';@Directive({ selector:'[appUnless]'})exportclassUnlessDirective{private hasView =false;constructor(private templateRef: TemplateRef<any>,private viewContainer: ViewContainerRef ){}@Input()setappUnless(condition:boolean){if(!condition &&!this.hasView){this.viewContainer.createEmbeddedView(this.templateRef);this.hasView =true;}elseif(condition &&this.hasView){this.viewContainer.clear();this.hasView =false;}}}
<!-- 使用自定义结构型指令 --><div*appUnless="isHidden">这段内容在 isHidden 为 false 时显示</div>

8. 管道 (Pipes)

管道用于转换数据显示格式。

示例:内置管道

<!-- 日期管道 --><p>{{ today | date:'yyyy-MM-dd' }}</p><p>{{ today | date:'full' }}</p><!-- 货币管道 --><p>{{ price | currency:'CNY':'symbol':'1.2-2' }}</p><!-- 数字管道 --><p>{{ number | number:'1.2-2' }}</p><!-- 百分比管道 --><p>{{ ratio | percent:'1.2-2' }}</p><!-- 大写/小写管道 --><p>{{ text | uppercase }}</p><p>{{ text | lowercase }}</p><!-- 切片管道 --><p>{{ longText | slice:0:100 }}...</p><!-- JSON 管道 --><pre>{{ object | json }}</pre>

示例:自定义管道

// truncate.pipe.tsimport{ Pipe, PipeTransform }from'@angular/core';@Pipe({ name:'truncate'})exportclassTruncatePipeimplementsPipeTransform{transform(value:string, limit:number=20, trail:string='...'):string{if(!value)return'';return value.length > limit ? value.substring(0, limit)+ trail : value;}}
// filter.pipe.tsimport{ Pipe, PipeTransform }from'@angular/core';@Pipe({ name:'filter', pure:false// 非纯管道,每次变更检测都会执行})exportclassFilterPipeimplementsPipeTransform{transform(items:any[], searchText:string):any[]{if(!items)return[];if(!searchText)return items; searchText = searchText.toLowerCase();return items.filter(item => item.name.toLowerCase().includes(searchText));}}
<!-- 使用自定义管道 --><p>{{ longText | truncate:50 }}</p><div*ngFor="let item of items | filter:searchText"> {{ item.name }} </div>

9. HTTP 客户端

Angular HttpClient 用于发送 HTTP 请求。

示例:GET 请求

// user.service.tsimport{ HttpClient, HttpParams }from'@angular/common/http';import{ Observable }from'rxjs';@Injectable({ providedIn:'root'})exportclassUserService{private apiUrl ='https://api.example.com/users';constructor(private http: HttpClient){}// 简单 GET 请求getUsers(): Observable<User[]>{returnthis.http.get<User[]>(this.apiUrl);}// 带查询参数的 GET 请求searchUsers(keyword:string, page:number=1): Observable<User[]>{const params =newHttpParams().set('keyword', keyword).set('page', page.toString());returnthis.http.get<User[]>(this.apiUrl,{ params });}// 带响应类型的 GET 请求downloadFile(): Observable<Blob>{returnthis.http.get(this.apiUrl +'/export',{ responseType:'blob'});}}

示例:POST/PUT/DELETE 请求

// user.service.tscreateUser(user: User): Observable<User>{returnthis.http.post<User>(this.apiUrl, user);}updateUser(id:number, user: Partial<User>): Observable<User>{returnthis.http.put<User>(`${this.apiUrl}/${id}`, user);}deleteUser(id:number): Observable<void>{returnthis.http.delete<void>(`${this.apiUrl}/${id}`);}

示例:HTTP 拦截器

// auth.interceptor.tsimport{ Injectable }from'@angular/core';import{ HttpRequest, HttpHandler, HttpEvent, HttpInterceptor }from'@angular/common/http';import{ Observable }from'rxjs';@Injectable()exportclassAuthInterceptorimplementsHttpInterceptor{intercept( request: HttpRequest<any>, next: HttpHandler ): Observable<HttpEvent<any>>{// 添加认证 tokenconst token = localStorage.getItem('token');if(token){ request = request.clone({ setHeaders:{ Authorization:`Bearer ${token}`}});}return next.handle(request);}}
// app.module.tsimport{HTTP_INTERCEPTORS}from'@angular/common/http'; providers:[{ provide:HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi:true}]

示例:错误处理

// user.service.tsimport{ catchError, retry }from'rxjs/operators';import{ throwError }from'rxjs';getUsers(): Observable<User[]>{returnthis.http.get<User[]>(this.apiUrl).pipe(retry(3),// 重试 3 次catchError(this.handleError));}privatehandleError(error:any){let errorMessage ='发生未知错误';if(error.error instanceofErrorEvent){ errorMessage =`错误: ${error.error.message}`;}else{ errorMessage =`错误代码: ${error.status}\n消息: ${error.message}`;}console.error(errorMessage);returnthrowError(()=> errorMessage);}

10. 表单 (Forms)

Angular 提供两种表单方式:模板驱动表单和响应式表单。

示例:模板驱动表单

// login.component.tsimport{ Component }from'@angular/core';@Component({ selector:'app-login', template:` <form #loginForm="ngForm" (ngSubmit)="onSubmit(loginForm)"> <div> <label>用户名:</label> <input name="username" ngModel required minlength="3" #username="ngModel"> <div *ngIf="username.invalid && username.touched"> <span *ngIf="username.errors?.['required']">用户名必填</span> <span *ngIf="username.errors?.['minlength']">至少3个字符</span> </div> </div> <div> <label>密码:</label> <input type="password" name="password" ngModel required> </div> <button type="submit" [disabled]="loginForm.invalid"> 登录 </button> </form> `})exportclassLoginComponent{onSubmit(form:any){if(form.valid){console.log('表单数据:', form.value);}}}

示例:响应式表单

// register.component.tsimport{ Component, OnInit }from'@angular/core';import{ FormBuilder, FormGroup, Validators, AbstractControl }from'@angular/forms';@Component({ selector:'app-register', template:` <form [formGroup]="registerForm" (ngSubmit)="onSubmit()"> <div> <label>邮箱:</label> <input formControlName="email"> <div *ngIf="email.invalid && email.touched"> <span *ngIf="email.errors?.['required']">邮箱必填</span> <span *ngIf="email.errors?.['email']">邮箱格式不正确</span> </div> </div> <div> <label>密码:</label> <input type="password" formControlName="password"> </div> <div> <label>确认密码:</label> <input type="password" formControlName="confirmPassword"> <div *ngIf="registerForm.errors?.['passwordMismatch']"> 密码不匹配 </div> </div> <button type="submit" [disabled]="registerForm.invalid"> 注册 </button> </form> `})exportclassRegisterComponentimplementsOnInit{ registerForm!: FormGroup;constructor(private fb: FormBuilder){}ngOnInit(){this.registerForm =this.fb.group({ email:['',[Validators.required, Validators.email]], password:['',[Validators.required, Validators.minLength(6)]], confirmPassword:['']},{ validators:this.passwordMatchValidator });}getemail(){returnthis.registerForm.get('email')!;}getpassword(){returnthis.registerForm.get('password')!;}getconfirmPassword(){returnthis.registerForm.get('confirmPassword')!;}passwordMatchValidator(control: AbstractControl){const password = control.get('password');const confirmPassword = control.get('confirmPassword');if(password && confirmPassword && password.value !== confirmPassword.value){return{ passwordMismatch:true};}returnnull;}onSubmit(){if(this.registerForm.valid){console.log('表单数据:',this.registerForm.value);}}}

示例:动态表单

// dynamic-form.component.tsimport{ Component }from'@angular/core';import{ FormArray, FormBuilder, FormGroup, Validators }from'@angular/forms';@Component({ selector:'app-dynamic-form', template:` <form [formGroup]="form"> <div formArrayName="hobbies"> <div *ngFor="let hobby of hobbies.controls; let i = index" [formGroupName]="i"> <input formControlName="name" placeholder="爱好名称"> <button type="button" (click)="removeHobby(i)">删除</button> </div> </div> <button type="button" (click)="addHobby()">添加爱好</button> </form> `})exportclassDynamicFormComponent{ form!: FormGroup;constructor(private fb: FormBuilder){this.form =this.fb.group({ hobbies:this.fb.array([])});}gethobbies(){returnthis.form.get('hobbies')as FormArray;}addHobby(){const hobbyGroup =this.fb.group({ name:['', Validators.required]});this.hobbies.push(hobbyGroup);}removeHobby(index:number){this.hobbies.removeAt(index);}}

11. 生命周期钩子 (Lifecycle Hooks)

组件生命周期钩子允许在组件生命周期的特定时刻执行代码。

Angular 组件生命周期(常用顺序与作用):

  1. constructor
    注入依赖,尽量不做复杂逻辑,不访问输入属性。
  2. ngOnChanges(changes: SimpleChanges)
    输入属性 @Input 变更时触发;首次也会触发。可根据 changes 做差异化处理。
  3. ngOnInit
    初始化时机,适合发起首次请求、初始化数据;此时可安全读取 @Input。
  4. ngDoCheck
    自定义变更检测钩子,谨慎使用,避免重计算导致性能问题。
  5. ngAfterContentInit / ngAfterContentChecked
    针对内容投影()的初始化/变更检查。
  6. ngAfterViewInit / ngAfterViewChecked
    视图(模板、子组件)初始化/变更后触发;此时可安全访问 @ViewChild/@ViewChildren。
  7. ngOnDestroy
    销毁前清理:取消订阅、清除计时器/监听、销毁资源。
    常用实践:
    数据初始化:放 ngOnInit。
    监听输入变化:用 ngOnChanges 或 @Input() set …。
    访问子组件/DOM:放 ngAfterViewInit。
    取消订阅:在 ngOnDestroy 里统一清理(如 takeUntil/Subscription.unsubscribe)。

示例:完整生命周期

// lifecycle.component.tsimport{ Component, OnInit, OnChanges, OnDestroy, AfterViewInit, AfterViewChecked, AfterContentInit, AfterContentChecked, DoCheck, Input, SimpleChanges }from'@angular/core';@Component({ selector:'app-lifecycle', template:'<div>{{ message }}</div>'})exportclassLifecycleComponentimplementsOnInit, OnChanges, DoCheck, AfterContentInit, AfterContentChecked, AfterViewInit, AfterViewChecked, OnDestroy {@Input() message ='';constructor(){console.log('1. constructor');}ngOnChanges(changes: SimpleChanges){console.log('2. ngOnChanges', changes);}ngOnInit(){console.log('3. ngOnInit');}ngDoCheck(){console.log('4. ngDoCheck');}ngAfterContentInit(){console.log('5. ngAfterContentInit');}ngAfterContentChecked(){console.log('6. ngAfterContentChecked');}ngAfterViewInit(){console.log('7. ngAfterViewInit');}ngAfterViewChecked(){console.log('8. ngAfterViewChecked');}ngOnDestroy(){console.log('9. ngOnDestroy - 清理资源');}}

示例:使用 ViewChild 和 AfterViewInit

// component.tsimport{ Component, ViewChild, AfterViewInit, ElementRef }from'@angular/core';@Component({ selector:'app-example', template:` <div #myDiv>内容</div> <app-child #child></app-child> `})exportclassExampleComponentimplementsAfterViewInit{@ViewChild('myDiv') myDiv!: ElementRef;@ViewChild('child') childComponent!: ChildComponent;ngAfterViewInit(){// 此时可以安全访问子组件和 DOM 元素console.log(this.myDiv.nativeElement.textContent);this.childComponent.doSomething();}}

12. RxJS 和 Observable

RxJS 是 Angular 中处理异步操作的核心库。

示例:基础 Observable

import{ Observable,of, from }from'rxjs';// 创建简单的 Observableconst simple$ =of(1,2,3); simple$.subscribe(value =>console.log(value));// 从数组创建const array$ =from([1,2,3]); array$.subscribe(value =>console.log(value));// 从 Promise 创建const promise$ =from(fetch('/api/data')); promise$.subscribe(response =>console.log(response));

示例:常用操作符

import{ map, filter, tap, catchError, switchMap, debounceTime }from'rxjs/operators';// map - 转换数据this.http.get<User[]>('/api/users').pipe(map(users => users.map(user => user.name))).subscribe(names =>console.log(names));// filter - 过滤数据this.http.get<User[]>('/api/users').pipe(filter(users => users.length >0)).subscribe(users =>console.log(users));// tap - 执行副作用操作this.http.get<User[]>('/api/users').pipe(tap(users =>console.log('获取到用户:', users))).subscribe();// switchMap - 切换 Observablethis.searchControl.valueChanges.pipe(debounceTime(300),switchMap(keyword =>this.searchUsers(keyword))).subscribe(results =>console.log(results));// catchError - 错误处理this.http.get<User[]>('/api/users').pipe(catchError(error =>{console.error('错误:', error);returnof([]);// 返回默认值})).subscribe();

示例:Subject 和 BehaviorSubject

import{ Subject, BehaviorSubject }from'rxjs';// Subject - 多播 ObservableexportclassMessageService{private messageSubject =newSubject<string>();public messages$ =this.messageSubject.asObservable();sendMessage(message:string){this.messageSubject.next(message);}}// BehaviorSubject - 带初始值的 SubjectexportclassStateService{private stateSubject =newBehaviorSubject<number>(0);public state$ =this.stateSubject.asObservable();updateState(value:number){this.stateSubject.next(value);}getCurrentState():number{returnthis.stateSubject.value;}}

示例:取消订阅

import{ Component, OnDestroy }from'@angular/core';import{ Subscription }from'rxjs';@Component({ selector:'app-example', template:'<div>{{ data }}</div>'})exportclassExampleComponentimplementsOnDestroy{ data:any;private subscription =newSubscription();ngOnInit(){// 方式1: 使用 Subscriptionconst sub1 =this.service.getData().subscribe(data =>{this.data = data;});this.subscription.add(sub1);// 方式2: 使用 takeUntilthis.service.getData().pipe(takeUntil(this.destroy$)).subscribe(data =>{this.data = data;});}ngOnDestroy(){this.subscription.unsubscribe();}}

13. 状态管理

示例:使用 Service 进行状态管理

// cart.service.tsimport{ Injectable }from'@angular/core';import{ BehaviorSubject, Observable }from'rxjs';exportinterfaceCartItem{ id:number; name:string; price:number; quantity:number;}@Injectable({ providedIn:'root'})exportclassCartService{private cartSubject =newBehaviorSubject<CartItem[]>([]);public cart$ =this.cartSubject.asObservable();getCart(): Observable<CartItem[]>{returnthis.cart$;}addItem(item: CartItem){const current =this.cartSubject.value;const existing = current.find(i => i.id === item.id);if(existing){ existing.quantity += item.quantity;}else{ current.push(item);}this.cartSubject.next([...current]);}removeItem(id:number){const current =this.cartSubject.value.filter(item => item.id !== id);this.cartSubject.next(current);}clearCart(){this.cartSubject.next([]);}getTotal():number{returnthis.cartSubject.value.reduce((sum, item)=> sum + item.price * item.quantity,0);}}

示例:使用 NgRx(状态管理库)

// cart.actions.tsimport{ createAction, props }from'@ngrx/store';import{ CartItem }from'./cart.model';exportconst addItem =createAction('[Cart] Add Item',props<{ item: CartItem }>());exportconst removeItem =createAction('[Cart] Remove Item',props<{ id:number}>());exportconst clearCart =createAction('[Cart] Clear');
// cart.reducer.tsimport{ createReducer, on }from'@ngrx/store';import{ addItem, removeItem, clearCart }from'./cart.actions';import{ CartItem }from'./cart.model';exportinterfaceCartState{ items: CartItem[];}exportconst initialState: CartState ={ items:[]};exportconst cartReducer =createReducer( initialState,on(addItem,(state,{ item })=>{const existing = state.items.find(i => i.id === item.id);if(existing){return{...state, items: state.items.map(i => i.id === item.id ?{...i, quantity: i.quantity + item.quantity }: i )};}return{...state, items:[...state.items, item]};}),on(removeItem,(state,{ id })=>({...state, items: state.items.filter(item => item.id !== id)})),on(clearCart, state =>({...state, items:[]})));
// component.tsimport{ Component }from'@angular/core';import{ Store }from'@ngrx/store';import{ Observable }from'rxjs';import{ addItem }from'./cart.actions';import{ CartState }from'./cart.reducer';@Component({ selector:'app-cart', template:` <div *ngFor="let item of items$ | async"> {{ item.name }} - {{ item.price }} </div> `})exportclassCartComponent{ items$: Observable<CartItem[]>;constructor(private store: Store<{ cart: CartState }>){this.items$ =this.store.select(state => state.cart.items);}addToCart(item: CartItem){this.store.dispatch(addItem({ item }));}}

14. 测试

示例:组件测试

// app.component.spec.tsimport{ TestBed }from'@angular/core/testing';import{ AppComponent }from'./app.component';describe('AppComponent',()=>{beforeEach(async()=>{await TestBed.configureTestingModule({ declarations:[AppComponent]}).compileComponents();});it('should create the app',()=>{const fixture = TestBed.createComponent(AppComponent);const app = fixture.componentInstance;expect(app).toBeTruthy();});it('should increment count',()=>{const fixture = TestBed.createComponent(AppComponent);const component = fixture.componentInstance;const initialCount = component.count; component.increment();expect(component.count).toBe(initialCount +1);});it('should render title',()=>{const fixture = TestBed.createComponent(AppComponent); fixture.detectChanges();const compiled = fixture.nativeElement;expect(compiled.querySelector('h1').textContent).toContain('我的 Angular 应用');});});

示例:服务测试

// user.service.spec.tsimport{ TestBed }from'@angular/core/testing';import{ HttpClientTestingModule, HttpTestingController }from'@angular/common/http/testing';import{ UserService }from'./user.service';describe('UserService',()=>{let service: UserService;let httpMock: HttpTestingController;beforeEach(()=>{ TestBed.configureTestingModule({ imports:[HttpClientTestingModule], providers:[UserService]}); service = TestBed.inject(UserService); httpMock = TestBed.inject(HttpTestingController);});afterEach(()=>{ httpMock.verify();});it('should fetch users',()=>{const mockUsers =[{ id:1, name:'张三', email:'[email protected]'},{ id:2, name:'李四', email:'[email protected]'}]; service.getUsers().subscribe(users =>{expect(users.length).toBe(2);expect(users).toEqual(mockUsers);});const req = httpMock.expectOne('/api/users');expect(req.request.method).toBe('GET'); req.flush(mockUsers);});});

总结

Angular 是一个功能强大的前端框架,主要特点包括:

  1. 组件化架构 - 可复用的组件系统
  2. 依赖注入 - 自动管理依赖关系
  3. 模块化 - 组织代码结构
  4. 路由系统 - 单页应用导航
  5. 响应式编程 - RxJS 处理异步操作
  6. 双向数据绑定 - 简化数据流
  7. 指令系统 - 扩展 HTML 功能
  8. 表单处理 - 强大的表单验证
  9. HTTP 客户端 - 处理 API 请求
  10. 测试支持 - 完整的测试工具

这些特性使得 Angular 非常适合构建大型、复杂的企业级应用。

下边是Angular项目结构示例

my-angular-app/
├─ angular.json # Angular CLI 配置
├─ package.json # 项目依赖与脚本
├─ tsconfig.json # TypeScript 编译配置
├─ tsconfig.app.json # 应用 TS 配置
├─ tsconfig.spec.json # 测试 TS 配置
├─ karma.conf.js # 单元测试(Karma)配置
├─ src/
│ ├─ main.ts # 应用入口(bootstrap AppModule)
│ ├─ index.html # 单页应用入口 HTML
│ ├─ styles.scss # 全局样式
│ ├─ polyfills.ts # 兼容性填充
│ ├─ environments/ # 环境变量(prod/dev)
│ │ ├─ environment.ts
│ │ └─ environment.prod.ts
│ ├─ app/
│ │ ├─ app.module.ts # 根模块
│ │ ├─ app.component.* # 根组件
│ │ ├─ core/ # 核心服务、拦截器、守卫(全局单例)
│ │ ├─ shared/ # 可复用组件、指令、管道、工具
│ │ ├─ features/ # 业务功能模块(按域拆分)
│ │ │ ├─ home/ # 示例功能模块
│ │ │ ├─ users/ # 示例功能模块
│ │ │ └─ … # 其它业务域
│ │ ├─ services/ #(可选)跨功能通用服务
│ │ ├─ models/ #(可选)接口/类型定义
│ │ ├─ guards/ #(可选)路由守卫
│ │ ├─ interceptors/ #(可选)HTTP 拦截器
│ │ ├─ store/ #(可选)状态管理(NgRx、Akita 等)
│ │ └─ app-routing.module.ts # 根路由
│ └─ assets/ # 静态资源(图片、字体、i18n 等)
└─ e2e/ # 端到端测试(如使用 Cypress/Protractor)

Read more

Mission Planner完整实战教程:免费无人机飞行控制与任务规划深度指南

Mission Planner完整实战教程:免费无人机飞行控制与任务规划深度指南 【免费下载链接】MissionPlanner 项目地址: https://gitcode.com/gh_mirrors/mis/MissionPlanner 想要轻松掌握无人机飞行控制与任务规划?Mission Planner作为一款功能强大的免费开源地面站软件,专门为ArduPilot系统设计,为你提供从基础飞行到专业应用的完整解决方案。无论你是无人机新手还是资深玩家,这款工具都能满足你的各种飞行需求。 🚀 快速上手:新手入门五步法 第一步:软件安装与环境配置 首先从项目仓库克隆最新版本,确保系统已安装.NET Framework运行环境。整个安装过程简单快捷,几分钟内就能完成所有准备工作。 第二步:设备连接与基础设置 通过Controls目录中的连接控制组件,轻松配置无人机通信参数。选择合适的串口和波特率,建立稳定的MAVLink连接,为后续飞行打下坚实基础。 第三步:初次飞行体验 从简单的直线飞行开始,逐步熟悉Mission Planner的操作界面。利用PreFlight目录

构建机器人集群系统:ROS 2分布式控制实战指南

构建机器人集群系统:ROS 2分布式控制实战指南 【免费下载链接】PX4-AutopilotPX4 Autopilot Software 项目地址: https://gitcode.com/gh_mirrors/px/PX4-Autopilot 本文将系统讲解如何基于ROS 2构建机器人集群系统,涵盖分布式控制技术原理、核心组件架构、快速部署流程及仓储场景应用。通过从零搭建多机器人协同框架,掌握分布式任务调度与异构机器人协作的关键技术,解决多机通信延迟、任务冲突等核心问题,为工业级机器人集群应用提供完整技术方案。 🔥 技术原理实现方案 机器人集群系统通过分布式控制架构实现多智能体协同,核心在于解决三个关键问题:节点间状态一致性、任务动态分配和实时通信保障。与传统集中式控制相比,分布式架构具有更高的容错性和扩展性,单个节点故障不会导致整个系统瘫痪。 分布式控制的核心算法包括: * 基于一致性协议的状态同步(如Raft算法) * 分布式任务分配的匈牙利算法 * 冲突避免的分布式路径规划 图1:机器人集群分布式控制架构示意图,展示状态感知、任务规划、执行控制的分层协作

Flutter for OpenHarmony 开发指南(五):实现tabbar主菜单功能

Flutter for OpenHarmony 开发指南(五):实现tabbar主菜单功能

前言 无论是在 Android、iOS 还是新兴的 HarmonyOS 平台上,底部标签栏都是用户与应用核心功能进行交互的主要入口。它提供了一种清晰、直观的导航方式,让用户可以轻松地在不同功能模块之间切换。 在本文中,将从一个只有独立页面的初始项目开始,一步步地重构代码,最终实现一个包含“首页”和“我的”两个核心模块的 TabBar 导航结构。 目标 我的目标是将一个通过路由进行离散页面跳转的应用,改造成一个拥有固定底部导航栏的现代化应用。 改造前: * 应用有一个初始页面。 * 所有页面(如登录、个人中心)通过 Navigator.pushNamed 等方法进行跳转,彼此独立。 * 没有一个统一的主导航结构。 改造后(我的目标): * 应用底部有一个常驻的 TabBar,包含“首页”和“我的”两个标签。 * 点击不同的标签,可以切换中间的主体内容区域,而 TabBar 本身保持不变。 * 页面切换流畅,

SLAM Toolbox:工业级机器人定位与建图解决方案

SLAM Toolbox:工业级机器人定位与建图解决方案 【免费下载链接】slam_toolboxSlam Toolbox for lifelong mapping and localization in potentially massive maps with ROS 项目地址: https://gitcode.com/gh_mirrors/sl/slam_toolbox 技术挑战与核心价值 在现代工业自动化和机器人应用中,大规模环境下的实时定位与地图构建面临着多重技术挑战:传感器噪声累积、长期运行漂移、多机器人协同通信瓶颈以及动态环境适应性不足。SLAM Toolbox作为专为工业场景设计的开源解决方案,通过模块化架构和优化算法,有效解决了这些痛点问题。 核心架构解析 分层处理架构 SLAM Toolbox采用四层架构设计,确保工业级应用的可靠性和可扩展性: 数据采集层 * 支持多种激光雷达协议,包括SICK、Hokuyo和Velodyne系列 * 兼容ROS 1和ROS 2通信标准 * 提供传感器数据质量监控和异常检测