網站搜尋

javascript - Angular 中的動態插件


問題是如何在 Angular 2+ 中實現類似我在 AngularJS 中做的 「事情」。下面我將描述這個 「事情」 是什麼。

問題描述

所以我在 AngularJS 中創建的這個過程可以描述如下:

  • 我們想在頁面中注入自訂的動態內容,我們稱它為插件
  • 該內容 在網頁客戶端中未定義,而是以結構化形式從伺服器檢索

也就是說,我們從伺服器接收插件運作所需的 html 和 js 檔案,然後在頁面上加載和顯示。在客戶端,我創建了一個 AngularJs 指令來承載插件所需的邏輯。

這裡是 JavaScript 插件代碼的範例:

() => {
    return {
        templateUrl: 'directive-template-name',
        restrict: "E",
        controller: ['$scope', ... /* other dependecies */, function ($scope, ...) {
            /* directive code */
        }]
    };
}

這裡是插件加載程式碼的範例:

// evaluate js function and compile directive
var diretiveFactory = eval(content.jsFile);

// AngularJS CompileProvider
CompileProvider.directive.apply(null, [content.name, diretiveFactory]);

// append html code to element using angular
var wrapper = angular.element("#" + wrapperName);
wrapper.html(requestedDirective[0].htmlContent);

// initialize dynamic content
var wrapperScope = wrapper.scope();
this.$compile(wrapper)(wrapperScope);

如同所見,這種方法允許載入一個有效的 JavaScript 並將其 「編譯」 成 AngularJS 指令,然後可以隨意在頁面上顯示它。

Angular 2+

新 Angular 的問題在於,據我理解,指令的概念被 元件 的概念所取代。此外,所有客戶端代碼現在都是用 TypeScript 編寫,並轉譯為客戶端瀏覽器的 JavaScript。據我理解,所有依賴都是在轉譯過程中解決的。

這會造成一些問題,阻礙為 Angular 2+ 創建動態插件:

  • 我不知道如何將依賴注入到動態創建的組件中,因為我不知道在轉譯發生時我到底需要什麼。
  • 假設我想讓幾個元件同時共存(例如一個包含子元件的父動態元件)並能夠互相通信,在 AngularJs 的情況下,我可以使用作用域變數來解決這個問題。在 Angular 2+ 的情況下,元件是隔離的,那麼我該如何處理這個問題呢。
  • 此外,我不知道如何在評估過的 JavaScript 代碼中創建 ViewContainerRef 來容納動態創建的組件。(參見下面的代碼範例)

我將在下面提供我目前為止獲得的程式碼範例。內容載入器 TypeScript 程式碼:

//some imports
import { Component, ComponentRef, Compiler, Injector, NgModule, NgModuleRef, ViewContainerRef} from '@angular/core';

// plugin content structure
class DynamicPageModel {
    name: string;
    htmlFile: string;
    jsFile: string;
}

export class DynamicContentService {

    constructor(
        private _compiler: Compiler,
        private _injector: Injector,
        private _m: NgModuleRef<any>
    ) { }

    public LoadDynamicContent(container: ViewContainerRef, content: DynamicPageModel) {
        // evaluate js function and compile component
        var tmpCmp = Component({
            template: content.htmlFile,
            selector: content.name
        })(eval(content.jsFile)());
        var tmpModule = NgModule({declarations: [tmpCmp as any]})(class { });
        var factories = this._compiler.compileModuleAndAllComponentsSync(tmpModule)
        var f = factories.componentFactories[0];

        var cmpRef =  f.create(this._injector, [], null, this._m);

        // insert component into the container
        container.insert(cmpRef.hostView);
    }
}

關於這段程式碼的內容,供參考,我是從這裡得到的。

插件範例 JavaScript 代碼:

() => {
    function dynamicMain() {
        this.componentName = 'Dynamic Example Main';
    }
    return dynamicExampleMain;
}

正如人們所見,這是一個相當簡單的動態插件,無法使用任何服務或其他元件,因為它無法將它們注入到自身。

預期的答案

作為對我問題的回答,我希望聽到對我在嘗試為 Angular 2+ 創建動態插件時遇到的問題的解決方案。

如果你知道在 Angular 2+ 中運行時創建動態插件(記住:它們是從伺服器獲取的)的更好方法,我也想聽聽。