Angular 2/5中如何将Material DOM元素追加到表单?
当然可行!你现在遇到的问题本质是:直接把HTML字符串塞进DOM里,Angular根本没机会编译这些Material组件——毕竟Angular的组件需要经过编译、实例化,才能变成带样式和交互的UI元素,直接插原始HTML自然只会显示一堆裸标签。
下面给你两种靠谱的解决方案,优先推荐第一种(更符合Angular的最佳实践):
方案一:用动态组件加载(最稳定)
这种方式是Angular官方推荐的动态添加组件的方法,能确保Material组件被正确渲染。
1. 创建一个包装动态内容的组件
先把你要插入的Material内容封装成一个独立的组件:
// dynamic-mat-actions.component.ts import { Component } from '@angular/core'; @Component({ template: ` <mat-card-actions> <button mat-button>LIKE</button> <button mat-button>SHARE</button> </mat-card-actions> ` }) export class DynamicMatActionsComponent {}
2. 在模块中配置依赖
确保你的模块(比如AppModule或者对应feature模块)中导入了Material相关模块,并且声明这个动态组件:
// 你的模块文件(比如app.module.ts) import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; // 导入Material所需模块 import { MatButtonModule } from '@angular/material/button'; import { MatCardModule } from '@angular/material/card'; import { FormComponent } from './form.component'; import { DynamicMatActionsComponent } from './dynamic-mat-actions.component'; @NgModule({ declarations: [ FormComponent, DynamicMatActionsComponent ], imports: [ BrowserModule, BrowserAnimationsModule, MatButtonModule, MatCardModule ] }) export class AppModule {}
3. 在FormComponent中动态创建组件
首先修改你的表单模板,添加一个用来承载动态组件的容器:
<!-- form.component.html --> <!-- 这个容器会用来放置动态生成的Material组件 --> <div #dynamicContainer></div> <button (click)="add()">添加Material按钮组</button>
然后在form.component.ts中,通过ViewContainerRef和ComponentFactoryResolver来动态创建组件:
// form.component.ts import { Component, ViewChild, ViewContainerRef, ComponentFactoryResolver } from '@angular/core'; import { DynamicMatActionsComponent } from './dynamic-mat-actions.component'; @Component({ selector: 'app-form', templateUrl: './form.component.html' }) export class FormComponent { // 获取承载动态组件的容器 @ViewChild('dynamicContainer', { read: ViewContainerRef }) dynamicContainer: ViewContainerRef; constructor(private componentFactoryResolver: ComponentFactoryResolver) {} public add() { // 可选:先清空容器里已有的内容 this.dynamicContainer.clear(); // 创建动态组件的工厂 const componentFactory = this.componentFactoryResolver.resolveComponentFactory(DynamicMatActionsComponent); // 在容器中实例化组件 const componentRef = this.dynamicContainer.createComponent(componentFactory); // 如果需要给动态组件传递数据,可以这样做 // componentRef.instance.yourProperty = 'some value'; } }
方案二:动态编译模板(适合需要从外部加载HTML的场景)
如果你必须从外部文件(比如你原来的txt.html)加载HTML内容,那可以用HttpClient获取内容后动态编译组件,但注意这种方式在生产环境(AOT编译)需要额外配置,因为默认AOT不支持动态编译。
1. 获取外部HTML内容并动态编译
// form.component.ts import { HttpClient } from '@angular/common/http'; import { Compiler, NgModule, ViewContainerRef } from '@angular/core'; import { MatButtonModule } from '@angular/material/button'; import { MatCardModule } from '@angular/material/card'; @Component({ selector: 'app-form', templateUrl: './form.component.html' }) export class FormComponent { constructor( private http: HttpClient, private compiler: Compiler, private viewContainerRef: ViewContainerRef ) {} async add() { // 加载外部HTML文件 const template = await this.http.get('./txt.html', { responseType: 'text' }).toPromise(); // 动态创建组件类 const dynamicComponent = Component({ template })(class {}); // 动态创建模块(必须导入Material相关模块) const dynamicModule = NgModule({ imports: [MatButtonModule, MatCardModule], declarations: [dynamicComponent] })(class {}); // 编译模块和组件 const moduleFactory = await this.compiler.compileModuleAsync(dynamicModule); const componentFactory = moduleFactory.componentFactoryResolver.resolveComponentFactory(dynamicComponent); // 清空容器并创建组件 this.viewContainerRef.clear(); this.viewContainerRef.createComponent(componentFactory); } }
2. 生产环境注意事项
这种方式在生产环境需要修改angular.json的构建配置,禁用AOT或者开启动态编译支持,但一般不推荐生产环境使用,会增加包体积和性能开销。
关键提醒
不管用哪种方式,都要确保你已经导入了对应的Material模块(比如MatButtonModule、MatCardModule),并且添加了BrowserAnimationsModule,否则Material组件的样式和动画都不会生效。
内容的提问来源于stack exchange,提问作者Nico Schuck

