Angular advanced featuresoverview
Angular providing了 many 种advanced features, 用于提升application performance, 可maintenance性 and user体验. 这些featuresincluding懒加载, 预加载策略, 动态component, 国际化, 单元test and 端 to 端testetc..
提示
合理using Angular advanced features可以显著提升application performance and Developmentefficiency, 但需要根据application 具体requirementsfor选择 and configuration.
1. 懒加载
懒加载 is 指 in 需要时才加载module, 而不 is in application启动时就加载所 has module. 这可以显著reducingapplication 初始加载时间.
1.1 configuration懒加载
// app-routing.module.ts
const routes: Routes = [
// otherroutingconfiguration
{
path: 'admin',
loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule) // 懒加载 AdminModule
}
];
1.2 creation懒加载module
ng generate module admin --route admin --module app
1.3 懒加载module routingconfiguration
// admin-routing.module.ts
const routes: Routes = [
{ path: '', component: AdminComponent },
{ path: 'users', component: UsermanagementmentComponent },
{ path: 'products', component: ProductmanagementmentComponent }
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class AdminRoutingModule { }
2. 预加载策略
预加载策略 is 指 in application启动 after , in after 台预加载懒加载module, 以提升user体验. Angular providing了 many 种预加载策略.
2.1 in 置预加载策略
// app-routing.module.ts
import { PreloadAllModules, RouterModule, Routes } from '@angular/router';
const routes: Routes = [
// routingconfiguration
];
@NgModule({
imports: [RouterModule.forRoot(routes, {
preloadingStrategy: PreloadAllModules // 预加载所 has 懒加载module
})],
exports: [RouterModule]
})
export class AppRoutingModule { }
2.2 自定义预加载策略
// selective-preload-strategy.ts
import { PreloadingStrategy, Route } from '@angular/router';
import { Observable, of } from 'rxjs';
export class SelectivePreloadStrategy implements PreloadingStrategy {
preload(route: Route, load: () => Observable): Observable {
if (route.data && route.data['preload']) {
return load(); // 预加载该module
}
return of(null); // 不预加载该module
}
}
// app-routing.module.ts
const routes: Routes = [
{
path: 'admin',
loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule),
data: { preload: true } // 标记 for 需要预加载
},
{
path: 'user',
loadChildren: () => import('./user/user.module').then(m => m.UserModule),
data: { preload: false } // 标记 for 不需要预加载
}
];
@NgModule({
providers: [SelectivePreloadStrategy],
imports: [RouterModule.forRoot(routes, {
preloadingStrategy: SelectivePreloadStrategy // using自定义预加载策略
})],
exports: [RouterModule]
})
export class AppRoutingModule { }
3. 动态component
动态component is 指 in run时根据条件creation and 销毁 component. 这可以用于implementation模态框, 弹窗, 动态表单etc.functions.
3.1 creation动态component
// dynamic-component-host.directive.ts
import { Directive, ViewContainerRef } from '@angular/core';
@Directive({
selector: '[appDynamicComponentHost]'
})
export class DynamicComponentHostDirective {
constructor(public viewContainerRef: ViewContainerRef) { }
}
// dynamic-component.component.ts
import { Component, ComponentFactoryResolver, ViewChild, OnInit } from '@angular/core';
import { DynamicComponentHostDirective } from './dynamic-component-host.directive';
import { HelloComponent } from './hello.component';
import { GoodbyeComponent } from './goodbye.component';
@Component({
selector: 'app-dynamic-component',
template: `
动态component
`
})
export class DynamicComponentComponent implements OnInit {
@ViewChild(DynamicComponentHostDirective, { static: true }) hostDirective: DynamicComponentHostDirective;
constructor(private componentFactoryResolver: ComponentFactoryResolver) { }
ngOnInit(): void {
}
loadHelloComponent() {
const componentFactory = this.componentFactoryResolver.resolveComponentFactory(HelloComponent);
const viewContainerRef = this.hostDirective.viewContainerRef;
viewContainerRef.clear(); // 清除之 before component
viewContainerRef.createComponent(componentFactory); // creation new component
}
loadGoodbyeComponent() {
const componentFactory = this.componentFactoryResolver.resolveComponentFactory(GoodbyeComponent);
const viewContainerRef = this.hostDirective.viewContainerRef;
viewContainerRef.clear(); // 清除之 before component
viewContainerRef.createComponent(componentFactory); // creation new component
}
}
// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { DynamicComponentComponent } from './dynamic-component/dynamic-component.component';
import { HelloComponent } from './dynamic-component/hello.component';
import { GoodbyeComponent } from './dynamic-component/goodbye.component';
import { DynamicComponentHostDirective } from './dynamic-component/dynamic-component-host.directive';
@NgModule({
declarations: [
AppComponent,
DynamicComponentComponent,
HelloComponent,
GoodbyeComponent,
DynamicComponentHostDirective
],
imports: [BrowserModule],
providers: [],
bootstrap: [AppComponent],
entryComponents: [HelloComponent, GoodbyeComponent] // register动态component
})
export class AppModule { }
4. 国际化
国际化 is 指将application适配 to 不同 language and 地区. Angular providing了 in 置 国际化support.
4.1 installation国际化依赖
npm install @angular/localize --save
4.2 标记可翻译文本
// using i18n 指令标记可翻译文本
欢迎来 to 我 application
这 is a using Angular Development application.
// using i18n-placeholder 标记占位符
4.3 提取可翻译文本
ng extract-i18n --output-path src/locale
4.4 creationlanguagefile
copy生成 messages.xlf file, 并rename for messages.zh.xlf, 然 after 翻译其in 文本.
4.5 configuration many languagesupport
// angular.json
{
"projects": {
"my-app": {
"i18n": {
"sourceLocale": "en-US",
"locales": {
"zh": {
"translation": "src/locale/messages.zh.xlf"
}
}
},
"architect": {
"build": {
"options": {
"localize": true
}
}
}
}
}
}
5. 单元test
单元test is 指testapplicationin 单个component, service or 指令. Angular in 置了 for 单元test support, using Jasmine and Karma.
5.1 run单元test
ng test
5.2 creation单元test
// app.component.spec.ts
import { TestBed, async } from '@angular/core/testing';
import { AppComponent } from './app.component';
describe('AppComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
AppComponent
],
}).compileComponents();
}));
it('应该creationapplication', () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app).toBeTruthy();
});
it(`应该 has 标题 'my-app'`, () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app.title).toEqual('my-app');
});
it('应该 in 页面in显示标题', () => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
const compiled = fixture.nativeElement;
expect(compiled.querySelector('.content span').textContent).toContain('my-app app is run!');
});
});
6. 端 to 端test
端 to 端test is 指test整个application 流程, from user 角度mockuser交互. Angular using Protractor for端 to 端test.
6.1 run端 to 端test
ng e2e
6.2 creation端 to 端test
// app.e2e-spec.ts
import { browser, by, element } from 'protractor';
describe('workspace-project App', () => {
beforeEach(() => {
browser.get(browser.baseUrl);
});
it('应该显示欢迎message', () => {
expect(element(by.css('h1')).getText()).toEqual('欢迎来 to 我 application');
});
it('应该导航 to 关于页面', () => {
element(by.linkText('About Us')).click();
expect(element(by.css('h2')).getText()).toEqual('About Us');
});
});
7. performanceoptimization
Angular providing了 many 种performanceoptimizationtechniques, 用于提升application runperformance.
7.1 using OnPush 变更检测策略
// component.ts
@Component({
selector: 'app-performance-component',
templateUrl: './performance-component.html',
changeDetection: ChangeDetectionStrategy.OnPush // using OnPush 变更检测策略
})
export class PerformanceComponent {
// componentcode
}
7.2 using trackBy optimization ngFor
// template.html
- {{ item.name }}
// component.ts
trackByFn(index: number, item: any): number {
return item.id; // 返回唯一标识符
}
7.3 using虚拟滚动
npm install @angular/cdk --save
// module.ts
import { ScrollingModule } from '@angular/cdk/scrolling';
@NgModule({
imports: [
// othermodule
ScrollingModule
]
})
export class AppModule { }
// template.html
{{ item.name }}
8. best practices
- 合理using懒加载 and 预加载策略, 提升application 初始加载速度
- using OnPush 变更检测策略, reducing不必要 变更检测
- using trackBy optimization ngFor performance
- for 于 big 型list, using虚拟滚动
- for application添加适当 单元test and 端 to 端test
- 考虑国际化support, 使applicationable to适应不同 language and 地区
- using动态componentimplementation complex 交互functions
- 定期runperformanceanalysistool, optimizationapplicationperformance
练习 1: implementation懒加载
- creation一个名 for
dashboard懒加载module - in 懒加载moduleincreation两个component:
DashboardComponentandStatisticsComponent - configuration懒加载routing
- test懒加载 is 否正常工作
练习 2: using OnPush 变更检测策略
- creation一个component, 并设置
changeDetection: ChangeDetectionStrategy.OnPush - in componentinusing
@Input接收data - testcomponent 变更检测behavior