Angular的無選擇器(Selectorless)非官方實現
- 眾所周知,Angular的組件定義,使用的時候,必須生成一個自定義標籤;某些時候使用css佈局的時候,就會比較麻煩
- 雖然官方已經開始考慮實現無選擇器,但是目前還在規劃中,不知道要等多久
原理
- 眾所周知,結構型指令可以動態插入模板
- 模板內容可以自定義,並且也可以使用組件內的所有屬性和方法
- 那麼只需要將組件變成一個模板,即可實現
- 變成的方法也很簡單,在組件的html中,套一層
ng-template即可 - 那麼現在有了模板,只需要考慮如何使用模板
- 也非常簡單,動態創建組件,會返回組件的實例,通過實例就能拿到模板引用
- 既然有了模板引用,那麼就可以使用
viewContainerRef插入了 - 由於插入的是模板,組件僅僅進行了創建,所以並沒有組件的選擇器被插入
- 這也就實現了無選擇器組件
實現
- 以下代碼僅做原理展示,更詳細的部分請到倉庫中查看
- 指令
// 創建組件引用,僅存在於內存
this._componentRef = createComponent(this.selectlessOutlet(), {});
// 獲得實例化的組件,注意組件需要有templateRef來保存模板引用
const instance = this._componentRef.instance as {
templateRef: Signal<TemplateRef<any>>;
};
// 在結構型指令中插入模板(類似ngIf ngFor)
this.#viewContainerRef.createEmbeddedView(instance.templateRef());
// 綁定生命週期
this.#appRef.attachView(this._componentRef.hostView);
this._componentRef.changeDetectorRef.detectChanges();
- 無選擇器組件部分
<ng-template #templateRef> 123 </ng-template>
@Component({})
export class InsertComponent implements OnInit {
public templateRef = viewChild.required('templateRef');
}
- 調用部分
<ng-container *selectlessOutlet="InsertComponent;inputs:{}"> </ng-container>
限制
- 當然,這個方法有一些侷限性
ng-content實現會非常複雜;需要使用ng-template引用做輸入變量代替-
部分指令可能會受限,因為使用此種方法實現的組件相當於一個空殼,獲取不到真正的元素
因為此時
ElementRef獲取到的元素未在dom中
更快的使用?
-
皮影視圖目前已經支持了自定義的無選擇器組件定義,並且可以很方便的切換
皮影可以視為
ngx-formly的Pro plus版本,與ngx-formly有着類似的概念,但是支持邏輯更加清晰,更加安全,支持強類型,多框架等特性
最後
- 如果您有其他問題,歡迎郵箱
wszgrcy@gmail.com聯繫 - 無選擇器代碼倉庫
- 皮影視圖代碼倉庫
- 演示視頻