Ale*_*mov 1 dependency-injection typescript angular
假设我们有以下内容:
@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}`);
}
}
Run Code Online (Sandbox Code Playgroud)
这3个喷油器有什么区别?
this.injectorthis.viewContainerRef.injectorthis.viewContainerRef.parentInjector在上面的测试中,它们都是不同的实例。
首先,您在构造函数中获得的Injector是所谓的Merge Injector。
这是它的定义:
class Injector_ implements Injector {
constructor(private view: ViewData, private elDef: NodeDef|null) {}
...
}
Run Code Online (Sandbox Code Playgroud)
Angular 只获取视图数据和节点定义,并且可以在需要时通过createInjector函数实例化 Injector 实例:
export function createInjector(view: ViewData, elDef: NodeDef): Injector {
return new Injector_(view, elDef);
}
Run Code Online (Sandbox Code Playgroud)
现在让我们回到你的指令:
SomeDirective
|
deps
/ \
Injector ViewContainer
Run Code Online (Sandbox Code Playgroud)
创建指令实例 Angular 通过专用函数resolveDep解析依赖项
export function resolveDep(view, elDef) {
...
case ViewContainerRefTokenKey:
return asElementData(searchView, elDef.nodeIndex).viewContainer;
...
case InjectorRefTokenKey:
return createInjector(searchView, elDef);
...
}
Run Code Online (Sandbox Code Playgroud)
让我们假设你有一个像这样的组件:
@Component({
selector: 'my-app',
template: '<h2 appSome>Hello</h2>'
})
export class AppComponent {}
Run Code Online (Sandbox Code Playgroud)
在这种情况下:
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)
Run Code Online (Sandbox Code Playgroud)
ViewContainerRef实例是在创建视图节点的早期创建的。由于您需要ViewContainerRef通过 DI Angular 标记h2具有特殊标志的节点,因此它可以实例化此实例ViewContainerRef并将其存储在 h2 节点数据中。
if (nodeDef.flags & 16777216 /* EmbeddedViews */) {
nodeData.viewContainer = createViewContainerData(view, nodeDef, nodeData);
}
Run Code Online (Sandbox Code Playgroud)
export function createViewContainerData(
view: ViewData, elDef: NodeDef, elData: ElementData): ViewContainerData {
return new ViewContainerRef_(view, elDef, elData);
}
Run Code Online (Sandbox Code Playgroud)
所以,我们在这里:Injector和ViewContainer该点到相同的观点,并同elDef。
现在让我们看看 ViewContainerRef定义:
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);
}
...
}
Run Code Online (Sandbox Code Playgroud)
injector === viewContainerRef.injector => fail
Run Code Online (Sandbox Code Playgroud)
因为viewContainerRef.injector getter 创建了具有相同视图和 elDef 的 Injector新实例。
所以以下是正确的:
injector.view === viewContainerRef.injector.view
injector.elDef === viewContainerRef.injector.elDef
Run Code Online (Sandbox Code Playgroud)
injector === viewContainerRef.parentInjector => fail
Run Code Online (Sandbox Code Playgroud)
因为 parentInjector getter 将获得具有父视图和父 elDef 的 Injector 的新实例。
这里的父视图是主机视图,elDef 是我的应用程序。
viewContainerRef.injector === viewContainerRef.parentInjector => fail
Run Code Online (Sandbox Code Playgroud)
应该很明显,它们不相等,因为也指向不同的视图和 elDef 并且是通过new操作符创建的。
最后,您可以阅读:
| 归档时间: |
|
| 查看次数: |
622 次 |
| 最近记录: |