1.组件生命周期、通信方式
angular中,一个组件暂时不再用到时,就会被销毁。当再次回到需要用到时,会重新生成一个新的实例,所以组件是有一定声明周期的。
- ngOnchanges
- ngInit
- ngDoCheck
- ngAfterContentInit
- ngAfterContentChecked
- ngAfterViewInit
- ngAfterViewChecked
- ngOnDestroy
ngOnchanges 除第一次外,还会在输入属性发生变化时执行
ngAfterContentInit、ngAfterContentChecked 发生在 ng-content 投射完毕之后
ngAfterViewInit、ngAfterViewChecked 发生在子组件渲染完毕之后
每次变更检测会依次执行 ngOnchanges (如果输入属性没有变化则不执行)、ngDoCheck、ngAfterContentChecked、ngAfterViewChecked
2.如何缓存组件
RouteReuseStrategy
angular中默认使用了一个路由策略的提供商RouteReuseStrategy,自行覆盖掉即可
// CustomReuseStrategy implements RouteReuseStrategy
providers: [
{ provide: RouteReuseStrategy, useClass: CustomReuseStrategy }
],
3.组件如何通信(待实践)
父子组件间
- @Input、@Output
- 获取对方实例(@ViewChild、@Inject)
- RxJS Subject
- RxJS 多播
兄弟组件间
- 获取对方实例
- RxJS Subject
- RxJS 多播
4.如何动态创建、销毁组件
export class AboutComponent implements OnDestroy {
@ViewChild('container', {read: ViewContainerRef, static: true}) container;
componentRef: ComponentRef;
factory: ComponentFactory;
constructor(private resolver: ComponentFactoryResolver) {}
create() {
this.container.clear();
this.factory = this.resolver.resolveComponentFactory(AboutChildComponent);
this.componentRef = this.container.createComponent(this.factory);
}
ngOnDestroy(): void {
this.componentRef.destroy();
}
}
5.依赖注入
useClass 直接使用类生成实例作为依赖
useFactory 使用此工厂函数返回的实例作为依赖
@Component({
providers: [
{
provide: MsgService,
useFactory: (http, dep2, dep3) => {
return new MsgService();
},
deps: [ // 可继续添加工厂函数的依赖
Http,
new Inject(TheOpaqueToken), // OpaqueToken需要手动调用new Inject()
TheInjectionToken // InjectionToken不需要手动调用new Inject()
]
}
]
})
export class AboutComponent {
constructor(private msg: MsgService) {}
}
useValue直接使用一个值作为依赖
providers: [
{
provide: MsgService,
useValue: 'hi there'
// useValue: myConfig
}
]
useExisting 直接使用已经存在的实例作为依赖,存在就不会再去new一个。
providers: [
{
provide: MsgService,
useExisting: MsgService
}
]
token问题
token为非type时,如果直接使用字符串,容易造成冲突,特别是不清楚第三方模块细节时
const config = {};
{
provide: 'myConfigToken', useValue: config
}
为避免这个问题,引入了OpaqueToken,用new OpaqueToken('myConfig')来作为token,其值是唯一的
const CONFIG_TOKEN = new OpaqueToken('config');
providers: [
{
provide: CONFIG_TOKEN,
useValue: config
}
]
但OpaqueToken在factoryProvider中,作为deps的话,需要手动调用new Inject()
const API_URL_TOKEN = new OpaqueToken('apiUrl');
providers: [
{
provide: DataService,
useFactory: (http, apiUrl) => {
// create data service
},
deps: [
Http,
new Inject(API_URL_TOKEN)
]
}
]
所以最终又设计了InjectionToken,来改进这个问题。ng4之后,废除了OpaqueToken。
const API_URL = new InjectionToken('apiUrl');
providers: [
{
provide: DataService,
useFactory: (apiUrl) => {
// create data service
},
deps: [
API_URL
]
}
]
多级注入器
注入器分为模块注入器和组件注入器。组件和模块之间、父组件和子组件之间,形成了多级注入器。比如同一个token,MsgService,可能在Module、FatherComponent、ChildComponent都有提供商。那么选择哪一个呢,默认是从下往上查找提供商。
手动注入
除了使用new手动生成实例外,还有其他方式的手动注入方式。非type类型时就得手动注入。
使用Injector
export class AppComponent implements OnInit {
constructor(private injector: Injector) {}
ngOnInit(): void {
const config = this.injector.get(CONFIG);
}
}
使用属性装饰器@Inject
export class AppComponent {
constructor( @Inject(CONFIG) private config: any) {}
}
关于依赖注入的几个属性装饰器
@Inject 注入依赖
@Optional 当注入器里面没有找到token对应的依赖的时候返回null
@Self 仅从当前组件注入器里面查找依赖
@SkipSelf 跳过当前注入器,直接从父级注入器开始查找
@Host 仅从宿主元素注入器里面查找依赖,用在指令中
Multi Providers
const SOME_TOKEN: InjectionToken> = new InjectionToken("SomeToken");
const injector = Injector.create([
{ provide: SOME_TOKEN, useValue: "dependency one", multi: true },
{ provide: SOME_TOKEN, useValue: "dependency two", multi: true }
]);
const dependencies = injector.get(SOME_TOKEN);
console.log(dependencies); // ['dependency one', 'dependency two']
内置的token常量
PLATFORM_INITIALIZER 平台初始化之后调用的回调函数
APP_BOOTSTRAP_LISTENER:每个启动组件启动完成之后调用的回调函数
APP_INITIALIZER 应用初始化之前调用的回调函数
HTTP_INTERCEPTORS http拦截