Heim >Web-Frontend >js-Tutorial >Bringen Sie Ihnen Schritt für Schritt bei, wie Sie mit Angular CDK Portal dynamische Inhalte erstellen
Ich habe das dynamische Einfügen von Ansichten der nativen API bereits eingeführt und die Funktion kann bereits die meisten Verwendungsszenarien erfüllen. Es gibt jedoch einige Mängel, die die Notwendigkeit, Inhalte außerhalb der Angular-Anwendung einzufügen, noch nicht gelöst haben, und die Anweisungen können keine Eingabe- und Ausgabeinteraktionen mit dynamisch eingefügten Komponenten haben.
Glücklicherweise stellt Angular offiziell eine Reihe von Komponentenentwicklungskits, Component Dev Kit (CDK), als grundlegendes Werkzeug für die Entwicklung verschiedener Angular-Komponenten bereit, einschließlich „Portal“, das bei der Erstellung dynamischer Ansichten hilft.
Diese „dynamische Ansicht“ kann eine Komponente, ein TemplateRef- oder ein DOM-Element sein, die jeweils drei Portaltypen (ComponentPortal, TemplatePortal, DomPortal) entsprechen. Die abstrakte generische Basisklasse der drei ist Portal8742468051c85b06f0a0af9e3e506b5c
, die über drei Methoden verfügt: attachment (am Container anhängen), detach (aus dem Container entfernen), isAttached (bestimmen, ob die Ansicht im montierten Zustand). Portal8742468051c85b06f0a0af9e3e506b5c
,有三个方法:attach(挂载到容器)、detach(从容器移除)、isAttached(判断视图是否是挂载状态)。
而容器也是由一个抽象类 BasePortalOutlet
定义,和视图类似,包含 attach(给容器挂载视图)、detach(从容器移除视图)、dispose(销毁容器)、isAttached(是否有挂载视图)。它的主要实现是 DomPortalOutlet
类。用以挂载三种类型的动态视图。
先来看看三种动态视图的创建。
ComponentPortal
相比原生 API,要创建一个动态组件非常的简单,只需要把组件类传入 ComponentPortal
构造函数即可。
this.componentPortal = new ComponentPortal(ExampleComponent);
可以传入任意自定义的组件类,用以创建 ComponentPortal
对象,再动态插入视图中。
✨注意:Angular 9 后的版本推荐使用 Ivy 编译器,如果是老版本编译器,传入的组件类,需要在 Module 的 entryComponents
中声明,并且这个 Module 不能懒加载。
TemplatePortal
TemplatePortal 的构建,相比组件,多了一个参数(ViewContainerRef)。看过前一篇应该对它非常熟悉了,需要依赖它调用 createEmbeddedView()
来创建嵌入视图。这里通过构造注入,直接使用当前组件的 ViewContainerRef
实例。
<ng-template #testTemplate> <p>一些需要动态插入的内容.</p> </ng-template>
@ViewChild('testTemplate') templatePortalContent: TemplateRef<any>; constructor(private _viewContainerRef: ViewContainerRef) { } ngAfterViewInit() { this.templatePortal = new TemplatePortal( this.templatePortalContent, this._viewContainerRef ); }
除了通过构造函数,TemplatePortal 也有一个指令(CdkPortal)可以便捷创建。
<ng-template cdkPortal> <p>一些需要动态插入的内容.</p> </ng-template> <!-- 或写作 --> <!-- 和上面写法是一致的效果 --> <p *cdkPortal> 一些需要动态插入的内容. </p>
然后通过 @ViewChild
就可以获得 TemplatePortal
的实例了。
DomPortal
就像上面的示例通过 @ViewChild
获取 Template 实例来创建,类似的也可以获取 ElementRef 来创建动态的 DOM。
<div #domPortalContent><span>原生DOM内容</span></div>
@ViewChild('domPortalContent') domPortalContent: ElementRef<HTMLElement>; ngAfterViewInit() { this.domPortal = new DomPortal(this.domPortalContent); }
可以动态的将这段 DOM 转移到任意位置。要注意的是,转移之后,原来的数据绑定,或者绑定的指令可能不会再继续更新。
前面三种类型的 Portal 都说了可以渲染到任意位置,那具体怎么渲染呢?
CdkPortOutlet
最简单的就是通过 CdkPortOutlet 指令了:
<div> <ng-template [cdkPortalOutlet]="anyPortal"></ng-template> </div>
给 anyPortal
传值上面三个中任意的 Portal 实例,都会动态渲染到当前位置。
和原生 API 的指令不同,它可以自动判断是什么类型的 Portal。另外,它还有个额外的事件:attached
,通过这个事件,可以获取到挂载的组件实例,或者 TemplateRef。这也让和挂载组件的交互变得十分方便了。
构造容器实例
不过既然说了是可以渲染到任意位置,那自然也包括 Angular 应用外部,要渲染到应用之外,就需要咱们通过构造函数创建容器实例。
这个容器类就是 DomPortalOutlet
,它是 PortalOutlet
BasePortalOutlet
definiert, die der Ansicht ähnelt und Folgendes umfasst: attachment (die Ansicht an den Container anhängen), detach (die Ansicht aus dem Container entfernen), dispose ( Zerstöre den Container), isAttached ( Ob es eine gemountete Ansicht gibt). Seine Hauptimplementierung ist die Klasse DomPortalOutlet
. Wird zum Mounten von drei Arten dynamischer Ansichten verwendet.
Dynamische Inhalte erstellen
Sehen wir uns zunächst die Erstellung von drei dynamischen Ansichten an.constructor( private viewContainerRef: ViewContainerRef, @Inject(DOCUMENT) private document: any, private injector: Injector, private componentFactoryResolver: ComponentFactoryResolver ) { // 在<body>下创建外部宿主元素 const container = this.document.createElement('div'); container.classList.add('outside-portal-container'); this.outsideContainer = this.document.body.appendChild(container); // 获取应用实例 this.appRef = this.injector.get(ApplicationRef); // 创建外部容器 this.outsideOutlet = new DomPortalOutlet( this.outsideContainer, this.componentFactoryResolver, this.appRef, this.injector ); } // 在应用外部插入动态组件。 openComponentPortalOutSideAngularContext(): void { const componentPortal = new ComponentPortal(AlertComponent); const componentRef = this.outsideOutlet.attach(componentPortal); componentRef.instance.closeAlert.subscribe(() => { this.outsideOutlet.detach(); }); } // 在应用外部插入动态模板。 openTemplatePortalInsideAngularContext(): void { const templatePortal = new TemplatePortal(this.templatePortalContent, this.viewContainerRef); this.outsideOutlet.attach(templatePortal); }Sie können jede benutzerdefinierte Komponentenklasse übergeben, um ein
ComponentPortal
-Objekt zu erstellen und es dann dynamisch in die Ansicht einzufügen. entryComponents
des deklariert werden Modul, und dieses Modul kann nicht verzögert geladen werden. 🎜TemplatePortal🎜🎜🎜TemplatePortal hat einen Parameter mehr (ViewContainerRef) als die Komponente. Nachdem Sie den vorherigen Artikel gelesen haben, sollten Sie damit vertraut sein. Sie müssen sich darauf verlassen, dass Sie createEmbeddedView()
aufrufen, um eine eingebettete Ansicht zu erstellen. Hier wird durch Konstruktorinjektion direkt die ViewContainerRef
-Instanz der aktuellen Komponente verwendet. 🎜const injectionToken = new InjectionToken<any>('Sharing data with outside component portal'); const customInjector = Injector.create({ providers: [{ provide: CustomInjectionToken, useValue: 'test value' }] });
// 重点是第四个参数 new DomPortalOutlet(this.outsideContainer, this.componentFactoryResolver, this.appRef, customInjector);🎜Zusätzlich zum Konstruktor verfügt TemplatePortal auch über einen Befehl (CdkPortal), der einfach erstellt werden kann. 🎜
constructor(@Inject(injectionToken) public customData: any) {}🎜Dann können Sie eine Instanz von
TemplatePortal
über @ViewChild
erhalten. 🎜🎜🎜DomPortal🎜🎜🎜Genau wie im obigen Beispiel können Sie die Vorlageninstanz über @ViewChild
abrufen, um sie zu erstellen Holen Sie sich auch ElementRef, um ein dynamisches DOM zu erstellen. 🎜// 重点是第三个参数 new TemplatePortal(this.templatePortalContent, this.viewContainerRef, { customData:'test values' });rrreee🎜 kann dieses DOM dynamisch an einen beliebigen Ort verschieben. Es ist zu beachten, dass nach der Übertragung die ursprüngliche Datenbindung bzw. die gebundenen Anweisungen möglicherweise nicht mehr aktualisiert werden. 🎜🎜🎜In den Container einfügen🎜🎜🎜Die vorherigen drei Arten von Portalen haben gesagt, dass sie an jeder Position gerendert werden können, aber wie werden sie konkret gerendert? 🎜🎜🎜CdkPortOutlet🎜🎜🎜Der einfachste Weg ist die Übergabe des CdkPortOutlet-Befehls: 🎜rrreee🎜Übergeben Sie die oben genannten drei Werte an
anyPortal Jede Portalinstanz in wird dynamisch am aktuellen Standort gerendert. 🎜🎜Im Gegensatz zu nativen API-Befehlen kann es automatisch bestimmen, um welche Art von Portal es sich handelt. Darüber hinaus gibt es ein zusätzliches Ereignis: <code>attached
. Über dieses Ereignis können Sie die gemountete Komponenteninstanz oder TemplateRef abrufen. Dies macht auch die Interaktion mit montierten Komponenten sehr komfortabel. 🎜🎜🎜Container-Instanz erstellen🎜🎜🎜Aber da gesagt wird, dass es an jeder Position gerendert werden kann, schließt es natürlich auch außerhalb der Angular-Anwendung ein In die Anwendung rendern. Darüber hinaus müssen wir über den Konstruktor eine Containerinstanz erstellen. 🎜🎜Diese Containerklasse ist DomPortalOutlet
, eine Implementierungsunterklasse von PortalOutlet
. Seine Konstruktionsparameter sind hauptsächlich: Element (der DOM-Knoten der gemounteten Ansicht), ComponentFactoryResolver (wie im vorherigen Artikel, wird zum dynamischen Erstellen von Komponenten verwendet), appRef (die Gesamtinstanz der aktuellen Angular-Anwendung), Injector (Injektor, gewohnt). Abhängigkeiten übergeben). 🎜rrreee🎜Zusätzlich zum Mounten der Ansicht in DOM-Elementen außerhalb der Anwendung muss sie auch in der Lage sein, mit der Ansicht zu interagieren. Komponenten können Abhängigkeiten einfügen und Vorlagen können Kontextobjekte übergeben. 🎜rrreee🎜Ändern Sie den Code zum Erstellen von externalContainer leicht und übergeben Sie den customInjector als Parameter (anstatt den Injektor der aktuellen Komponente zu verwenden)🎜rrreee🎜Entsprechend muss diese Komponente nur Abhängigkeiten gemäß diesem Injektions-Token injizieren:🎜rrreee🎜Geben Beim Erstellen eines TemplatePortal-Objekts übergeben Sie einfach das Kontextobjekt: 🎜rrreee🎜🎜 Zusammenfassung🎜🎜🎜Im Vergleich zur nativen API implementiert das CDK-Portal hauptsächlich: 🎜🎜🎜🎜Dynamisches Einfügen von Ansichten außerhalb der Anwendung Fähigkeit; 🎜
Die Möglichkeit, mit von außen eingefügten Ansichtsdaten zu interagieren;
Bequemere und flexiblere Befehle.
Damit wird es einfacher, dynamische Komponentencontainer, Popup-Fenster, schwebende Menüs zu erstellen oder sogar eine Low-Code-Designplattform aufzubauen.
Projektquellcode: https://github.com/locotor/angular-dynamic-view-example
Online-Beispiel: https://coding-pages-bucket-1575455-8137703-14801-541995-1303365836.cos - website.ap-beijing.myqcloud.com/
Weitere Kenntnisse zum Thema Programmierung finden Sie unter: Einführung in die Programmierung! !
Das obige ist der detaillierte Inhalt vonBringen Sie Ihnen Schritt für Schritt bei, wie Sie mit Angular CDK Portal dynamische Inhalte erstellen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!