欧美亚洲中文,在线国自产视频,欧洲一区在线观看视频,亚洲综合中文字幕在线观看

      1. <dfn id="rfwes"></dfn>
          <object id="rfwes"></object>
        1. 站長資訊網(wǎng)
          最全最豐富的資訊網(wǎng)站

          手把手教你使用Angular CDK Portal創(chuàng)建動態(tài)內(nèi)容

          手把手教你使用Angular CDK Portal創(chuàng)建動態(tài)內(nèi)容

          之前介紹過原生 API 的動態(tài)視圖插入,功能上已經(jīng)可以滿足大多數(shù)使用場景。不過也有一些缺憾,還沒有解決在 Angular 應(yīng)用外插入內(nèi)容的需求,指令也不能跟動態(tài)插入的組件有輸入輸出的交互。

          好在 Angular 官方提供了一套組件開發(fā)套件 Component Dev Kit (CDK),作為各種 Angular 組件開發(fā)的基礎(chǔ)工具,其中就提供 “Portal(傳送門)” 來輔助動態(tài)視圖的創(chuàng)建。

          這個 ”動態(tài)視圖“ 可以是組件、TemplateRef 或者 DOM 元素,分別對應(yīng)三種 Portal 類型(ComponentPortal、TemplatePortal、DomPortal)。它們?nèi)齻€的抽象泛型基類是 Portal<T>,有三個方法:attach(掛載到容器)、detach(從容器移除)、isAttached(判斷視圖是否是掛載狀態(tài))。

          而容器也是由一個抽象類 BasePortalOutlet 定義,和視圖類似,包含 attach(給容器掛載視圖)、detach(從容器移除視圖)、dispose(銷毀容器)、isAttached(是否有掛載視圖)。它的主要實(shí)現(xiàn)是 DomPortalOutlet 類。用以掛載三種類型的動態(tài)視圖。

          創(chuàng)建動態(tài)內(nèi)容

          先來看看三種動態(tài)視圖的創(chuàng)建。

          ComponentPortal

          相比原生 API,要創(chuàng)建一個動態(tài)組件非常的簡單,只需要把組件類傳入 ComponentPortal 構(gòu)造函數(shù)即可。

          this.componentPortal = new ComponentPortal(ExampleComponent);

          可以傳入任意自定義的組件類,用以創(chuàng)建 ComponentPortal 對象,再動態(tài)插入視圖中。

          ✨注意:Angular 9 后的版本推薦使用 Ivy 編譯器,如果是老版本編譯器,傳入的組件類,需要在 Module 的 entryComponents 中聲明,并且這個 Module 不能懶加載。

          TemplatePortal

          TemplatePortal 的構(gòu)建,相比組件,多了一個參數(shù)(ViewContainerRef)。看過前一篇應(yīng)該對它非常熟悉了,需要依賴它調(diào)用 createEmbeddedView() 來創(chuàng)建嵌入視圖。這里通過構(gòu)造注入,直接使用當(dāng)前組件的 ViewContainerRef 實(shí)例。

          <ng-template #testTemplate>   <p>一些需要動態(tài)插入的內(nèi)容.</p> </ng-template>
          @ViewChild('testTemplate') templatePortalContent: TemplateRef<any>;  constructor(private _viewContainerRef: ViewContainerRef) { }  ngAfterViewInit() {   this.templatePortal = new TemplatePortal(     this.templatePortalContent,     this._viewContainerRef   ); }

          除了通過構(gòu)造函數(shù),TemplatePortal 也有一個指令(CdkPortal)可以便捷創(chuàng)建。

          <ng-template cdkPortal>   <p>一些需要動態(tài)插入的內(nèi)容.</p> </ng-template>  <!-- 或?qū)懽?-->  <!-- 和上面寫法是一致的效果 --> <p *cdkPortal>   一些需要動態(tài)插入的內(nèi)容. </p>

          然后通過 @ViewChild 就可以獲得 TemplatePortal 的實(shí)例了。

          DomPortal

          就像上面的示例通過 @ViewChild 獲取 Template 實(shí)例來創(chuàng)建,類似的也可以獲取 ElementRef 來創(chuàng)建動態(tài)的 DOM。

          <div #domPortalContent><span>原生DOM內(nèi)容</span></div>
          @ViewChild('domPortalContent') domPortalContent: ElementRef<HTMLElement>; ngAfterViewInit() {   this.domPortal = new DomPortal(this.domPortalContent); }

          可以動態(tài)的將這段 DOM 轉(zhuǎn)移到任意位置。要注意的是,轉(zhuǎn)移之后,原來的數(shù)據(jù)綁定,或者綁定的指令可能不會再繼續(xù)更新。

          插入容器

          前面三種類型的 Portal 都說了可以渲染到任意位置,那具體怎么渲染呢?

          CdkPortOutlet

          最簡單的就是通過 CdkPortOutlet 指令了:

          <div>   <ng-template [cdkPortalOutlet]="anyPortal"></ng-template> </div>

          anyPortal 傳值上面三個中任意的 Portal 實(shí)例,都會動態(tài)渲染到當(dāng)前位置。

          和原生 API 的指令不同,它可以自動判斷是什么類型的 Portal。另外,它還有個額外的事件:attached,通過這個事件,可以獲取到掛載的組件實(shí)例,或者 TemplateRef。這也讓和掛載組件的交互變得十分方便了。

          構(gòu)造容器實(shí)例

          不過既然說了是可以渲染到任意位置,那自然也包括 Angular 應(yīng)用外部,要渲染到應(yīng)用之外,就需要咱們通過構(gòu)造函數(shù)創(chuàng)建容器實(shí)例。

          這個容器類就是 DomPortalOutlet,它是 PortalOutlet 的實(shí)現(xiàn)子類。它的構(gòu)造參數(shù)主要是:Element(掛載視圖的DOM節(jié)點(diǎn))、ComponentFactoryResolver(和上篇一樣,用以動態(tài)構(gòu)建組件)、appRef(當(dāng)前 Angular 應(yīng)用的整體實(shí)例)、Injector(注入器,用于傳遞依賴)。

          constructor(   private viewContainerRef: ViewContainerRef,   @Inject(DOCUMENT) private document: any,   private injector: Injector,   private componentFactoryResolver: ComponentFactoryResolver ) {   // 在<body>下創(chuàng)建外部宿主元素   const container = this.document.createElement('div');   container.classList.add('outside-portal-container');   this.outsideContainer = this.document.body.appendChild(container);   // 獲取應(yīng)用實(shí)例   this.appRef = this.injector.get(ApplicationRef);   // 創(chuàng)建外部容器   this.outsideOutlet = new DomPortalOutlet(     this.outsideContainer,      this.componentFactoryResolver,      this.appRef,      this.injector   ); }  // 在應(yīng)用外部插入動態(tài)組件。 openComponentPortalOutSideAngularContext(): void {   const componentPortal = new ComponentPortal(AlertComponent);   const componentRef = this.outsideOutlet.attach(componentPortal);     componentRef.instance.closeAlert.subscribe(() => {       this.outsideOutlet.detach();     }); }  // 在應(yīng)用外部插入動態(tài)模板。 openTemplatePortalInsideAngularContext(): void {   const templatePortal = new TemplatePortal(this.templatePortalContent, this.viewContainerRef);   this.outsideOutlet.attach(templatePortal); }

          除了掛載視圖到應(yīng)用外的 DOM 元素中,還需要能夠跟視圖進(jìn)行數(shù)據(jù)交互,組件可以通過注入依賴,模板可以傳入上下文對象。

          const injectionToken = new InjectionToken<any>('Sharing data with outside component portal'); const customInjector = Injector.create({ providers: [{ provide: CustomInjectionToken, useValue: 'test value' }] });

          對創(chuàng)建 outsideContainer 的代碼稍作修改,把這個 customInjector 作為參數(shù)傳入(而不是使用當(dāng)前組件的 injector)

          // 重點(diǎn)是第四個參數(shù) new DomPortalOutlet(this.outsideContainer, this.componentFactoryResolver, this.appRef, customInjector);

          相應(yīng)的,這個組件只需要按這個 injectionToken 注入依賴即可:

          constructor(@Inject(injectionToken) public customData: any) {}

          給模板傳遞上下文就比較簡單了,在創(chuàng)建 TemplatePortal 對象時,傳入上下文對象即可:

          // 重點(diǎn)是第三個參數(shù) new TemplatePortal(this.templatePortalContent, this.viewContainerRef, { customData:'test values' });

          總結(jié)

          相比原生 API,CDK portal 主要實(shí)現(xiàn)了:

          • 動態(tài)插入視圖到應(yīng)用外部的能力;

          • 和插入到外部的視圖數(shù)據(jù)交互的能力;

          • 更加便捷和靈活的指令。

          有了它,創(chuàng)建動態(tài)的組件容器,或者彈窗,浮動菜單,甚至是搭建一個低代碼設(shè)計平臺,都變得更加容易了。

          項(xiàng)目源碼:https://github.com/locotor/angular-dynamic-view-example

          在線示例:https://coding-pages-bucket-1575455-8137703-14801-541995-1303365836.cos-website.ap-beijing.myqcloud.com/

          贊(0)
          分享到: 更多 (0)
          網(wǎng)站地圖   滬ICP備18035694號-2    滬公網(wǎng)安備31011702889846號