假设我们有以下内容:
@Directive({ selector: "[appSome]" })
export class SomeDirective {
public constructor(
private viewContainerRef: ViewContainerRef,
private injector: Injector,
) {
console.log(`injector === viewContainerRef.injector: ${injector === viewContainerRef.injector}`);
console.log(`injector === viewContainerRef.parentInjector: ${injector === viewContainerRef.parentInjector}`);
console.log(`viewContainerRef.injector === viewContainerRef.parentInjector: ${viewContainerRef.injector === viewContainerRef.parentInjector}`);
}
}
这3个注射器有什么区别?
this.injector
this.viewContainerRef.injector
this.viewContainerRef.parentInjector
在上面的测试中,它们都是不同的实例。
答案 0 :(得分:3)
首先,您在构造函数中获得的 Injector 是所谓的Merge Injector。
这是definition:
class Injector_ implements Injector {
constructor(private view: ViewData, private elDef: NodeDef|null) {}
...
}
Angular只接受视图数据和节点定义,并且只要通过createInjector函数需要实例化Injector实例:
export function createInjector(view: ViewData, elDef: NodeDef): Injector {
return new Injector_(view, elDef);
}
现在让我们回到你的指令:
SomeDirective
|
deps
/ \
Injector ViewContainer
创建指令实例Angular通过专用函数resolveDep
解析依赖关系export function resolveDep(view, elDef) {
...
case ViewContainerRefTokenKey:
return asElementData(searchView, elDef.nodeIndex).viewContainer;
...
case InjectorRefTokenKey:
return createInjector(searchView, elDef);
...
}
假设您有一个类似的组件:
@Component({
selector: 'my-app',
template: '<h2 appSome>Hello</h2>'
})
export class AppComponent {}
在这种情况下:
SomeDirective
|
deps
/ \
Injector ViewContainer
|| ||
\/ \/
resolveDep(AppComponent view, h2 elDef) resolveDep(AppComponent view, h2 elDef)
|| ||
\/ \/
createInjector viewContainerRef (AppComponent view, h2 elDef)
(created early)
||
\/
new Injector(AppComponent view, h2 elDef)
ViewContainerRef
实例是在视图节点创建期间创建的。由于您需要ViewContainerRef
通过具有特殊标志的DI Angular标记h2
节点,因此它可以在h2节点数据中实例化ViewContainerRef
和store此实例。
if (nodeDef.flags & 16777216 /* EmbeddedViews */) {
nodeData.viewContainer = createViewContainerData(view, nodeDef, nodeData);
}
export function createViewContainerData(
view: ViewData, elDef: NodeDef, elData: ElementData): ViewContainerData {
return new ViewContainerRef_(view, elDef, elData);
}
所以我们在这里:Injector
和ViewContainer
指向相同的视图和相同的elDef。
现在让我们看一下ViewContainerRef definition:
class ViewContainerRef_ implements ViewContainerData {
...
constructor(private _view: ViewData, private _elDef: NodeDef, private _data: ElementData) {}
...
get injector(): Injector { return new Injector_(this._view, this._elDef); }
get parentInjector(): Injector {
let view = this._view;
let elDef = this._elDef.parent;
while (!elDef && view) {
elDef = viewParentEl(view);
view = view.parent !;
}
return view ? new Injector_(view, elDef) : new Injector_(this._view, null);
}
...
}
<案例1
injector === viewContainerRef.injector => fail
因为 viewContainerRef.injector getter使用相同的视图和elDef创建Injector的新实例。
以下是真的:
injector.view === viewContainerRef.injector.view
injector.elDef === viewContainerRef.injector.elDef
<案例2
injector === viewContainerRef.parentInjector => fail
因为parentInjector getter将获得具有父视图和父elDef的Injector的新实例。
此处的父视图是主视图,elDef是我的应用程序。
<案例3viewContainerRef.injector === viewContainerRef.parentInjector => fail
由于指向不同的视图和elDef,并且通过new
运算符创建,显然它们不相等。
最后,您可以阅读:
<强> What you always wanted to know about Angular Dependency Injection tree 强>