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+ 中運行時創建動態插件(記住:它們是從伺服器獲取的)的更好方法,我也想聽聽。