Roy*_*mir 1 javascript angular
我有一个工作代码,该代码通过服务将任何组件注入HTML:
ModalWindow.ts:
@Component({
selector: 'modal-window'
template: `
<div class="modal-dialog" role="document">
<div class="modal-content"><ng-content></ng-content></div>
</div>
`
})
export class ModalWindow {
}
Run Code Online (Sandbox Code Playgroud)
Modalcontent.ts:
@Component({
selector: 'modal-content'
template: `
I'm beeing opened as modal!
`
})
export class ModalContent {
}
Run Code Online (Sandbox Code Playgroud)
ModalService.ts:
/*1*/ @Injectable()
/*2*/ export class ModalService {
/*3*/
/*4*/ constructor(private _appRef: ApplicationRef, private _cfr: ComponentFactoryResolver, private _injector: Injector) {
/*5*/ }
/*6*/
/*7*/ open(content: any) {
/*8*/ const contentCmpFactory = this._cfr.resolveComponentFactory(content);
/*9*/ const windowCmpFactory = this._cfr.resolveComponentFactory(ModalWindow);
/*10*/
/*11*/ const contentCmpt = contentCmpFactory.create(this._injector);
/*12*/ const windowCmpt = windowCmpFactory.create(this._injector, [[contentCmpt.location.nativeElement]]);
/*13*/
/*14*/ document.querySelector('body').appendChild(windowCmpt.location.nativeElement);
/*15*/
/*16*/ this._appRef.attachView(contentCmpt.hostView);
/*17*/ this._appRef.attachView(windowCmpt.hostView);
/*18*/ }
/*19*/ }
Run Code Online (Sandbox Code Playgroud)
应用程式:
@Component({
selector: 'my-app',
template: `
<button (click)="open()">Open modal window</button>
`,
})
Run Code Online (Sandbox Code Playgroud)
结果(单击一个调用此服务方法的按钮时):
我已经知道什么contentCmpFactory和windowCmpFactory有(线#8,9)
但是我不知道以后会发生什么。关于第11行,第12行-文档说“创建一个新组件”。
问题:
1行#12:怎么[[contentCmpt.location.nativeElement]]办?(文档说它的类型是 projectableNodes?: any[][] -它们是什么意思?)
2行14号:做[[windowCmpt.location.nativeElement]]什么?
3行#16,#17:如果已经需要,为什么又为什么需要它们appendChild?(docs说:附加视图,以便对其进行脏检查。-这样吗?)。
答案:
1) Angular ComponentFactory使用给定的元素注入器和可投影节点数组创建并创建组件实例
windowCmpFactory.create(this._injector, [[contentCmpt.location.nativeElement]]);
Run Code Online (Sandbox Code Playgroud)
1.1当角度将解决依赖关系时将使用元素注入器
const value = startView.root.injector.get(depDef.token, NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR);
Run Code Online (Sandbox Code Playgroud)
这也是没有延迟加载的应用程序依赖项解析算法的简单说明。使用延迟加载,看起来会更加复杂。
有关更多详细信息,请参见设计文档元素注射器与模块注射器
1.2可投影节点是节点元素,它们ng-content在组件模板中具有的“已投影”(包含)。
为了投影某些东西,我们的组件模板必须包含ng-contentnode。
@Component({
selector: 'modal-window',
template: `
<div class="modal-dialog">
<div class="modal-content">
<ng-content></ng-content> // <== place for projection
</div>
</div>
`
})
export class ModalWindow {
Run Code Online (Sandbox Code Playgroud)
我们可以在父组件模板中使用上述组件,如下所示:
<modal-window>
<modal-content></modal-content>
<div>Some other content</div>
</modal-window>
Run Code Online (Sandbox Code Playgroud)
因此,我们的最终结果将如下所示:
<modal-window>
<div class="modal-dialog">
<div class="modal-content">
<modal-content></modal-content> // our projectable nodes
<div>Some other content</div> // replaced ng-content
</div>
</div>
</modal-window>
Run Code Online (Sandbox Code Playgroud)
因此,当我们传递可投影节点以创建方法时
windowCmpFactory.create(this._injector, [[contentCmpt.location.nativeElement]]);
Run Code Online (Sandbox Code Playgroud)
我们做与上述相同的事情。
我们正在参考(contentCmpt.location)创建的早期contentCmpt组件的host元素。这是modal-content要素。然后,Angular将尽一切魔力将其投射ng-content到位。
在上面的示例中,我添加了一个div
<modal-window>
<modal-content></modal-content>
<div>Some other content</div> <== here
</modal-window>
Run Code Online (Sandbox Code Playgroud)
因此,实际代码应如下所示:
let div = document.createElement('div');
div.textContent = 'Some other content';
windowCmpFactory.create(this._injector, [[contentCmpt.location.nativeElement, div]]);
Run Code Online (Sandbox Code Playgroud)
结论为什么projectableNodes是any [] []?
2)在下一行
document.querySelector('body').appendChild(windowCmpt.location.nativeElement);
Run Code Online (Sandbox Code Playgroud)
我们正在引用在内存modal-window元素中创建的内容。ComponentRef允许我们执行此操作,因为它在locationgetter中存储了对host元素的引用
export abstract class ComponentRef<C> {
/**
* Location of the Host Element of this Component Instance.
*/
abstract get location(): ElementRef;
Run Code Online (Sandbox Code Playgroud)
然后将其插入document.body标记中作为最后一个孩子。所以我们在页面上看到它。
3)假设我们不仅ModalContent具有静态内容,还将执行一些交互操作。
@Component({
selector: 'modal-content',
template: `
I'm beeing opened as modal! {{ counter }}
<button (click)="counter = counter + 1">Increment</button>
`
})
export class ModalContent {
counter = 1;
}
Run Code Online (Sandbox Code Playgroud)
如果我们删除
this._appRef.attachView(contentCmpt.hostView);
Run Code Online (Sandbox Code Playgroud)
那么我们的视图将不会在更改检测周期内进行更新,因为我们通过创建了视图,ComponentFactory.create并且我们的视图不属于更改检测树中的任何项目(不同于通过创建ViewContainerRef.createComponent)。Angular为此目的打开了API,我们可以轻松地将视图添加到根views https://github.com/angular/angular/blob/master/packages/core/src/application_ref.ts#L428,此后,我们的组件将在Application.tick https://github.com/angular/angular/blob/master/packages/core/src/application_ref.ts#L558
| 归档时间: |
|
| 查看次数: |
843 次 |
| 最近记录: |