这个问题专门针对 SVG 组件,即使用 svg 模板的组件。我知道如何在 Angular 18 中动态创建组件,这个问题比这个更具体,因为它是关于动态创建 svg 组件。
我已经创建了必要的 github 存储库来支持这个问题,可以在here
找到它那么进入正题,这可能更多的是关于如何在动态创建的组件中使用属性选择器,但我不想引导见证人。
期望的结果是能够拥有某种容纳
<svg>
元素的容器组件,并能够动态添加容纳 svg 元素的特定组件。
所以在这个例子中
export class DrawingSurfaceComponent {
@ViewChild('svgRef', { read: ViewContainerRef })
svgRef!: ViewContainerRef;
registry:any[] = [];
registerDrawingElementType(drawingElementType:any){
this.registry.push(drawingElementType);
}
drawElement(drawingElementName:string){
const [ el ] = this.registry.filter(r => r.name = drawingElementName);
const newComponentRef = this.svgRef.createComponent(el.elementType);
}
}
使用以下模板
<svg>
<g #svgRef></g>
</svg>
我想要的是 drawElement 方法动态添加我的矩形组件,从而产生以下输出
<svg>
<g>
<rect ... >
</g>
</svg>
相反我得到的是
<svg>
<g>
<app-rectangle _nghost-ng-c578836850=""><rect _ngcontent-ng-c578836850="" width="200" height="100" x="10" y="10" rx="20" ry="20" fill="blue"></rect></app-rectangle>
</g>
</svg>
鉴于 app-rectangle 不是有效的 svg,因此不会绘制矩形。
如果我尝试使用像这样的属性选择器
@Component({
selector: '[my-rect]',
standalone: true,
imports: [],
templateUrl: './rectangle.component.html',
styleUrl: './rectangle.component.css',
schemas: [
NO_ERRORS_SCHEMA
]
})
export class RectangleComponent {
}
使用以下模板
<rect my-rect width="200" height="100" x="10" y="10" rx="20" ry="20" fill="blue" />
我根本没有任何输出
<svg _ngcontent-ng-c3197269335=""><g _ngcontent-ng-c3197269335=""></g><!--container--></svg>
那么我如何在 Angular 18 中实现这一目标?
奇怪的是,假设你有这个 HTML:
<svg>
<g #svgRef></g>
</svg>
和跑步
this.svgRef.createComponent(el.elementType);
你得到:
<svg>
<g>
<app-rectangle ...></rect></app-rectangle>
</g>
</svg>
您
app-rectangle
组件应添加为 <g>
的兄弟组件,而不是其子组件:
<svg>
<g></g>
<app-rectangle ...></rect></app-rectangle>
</svg>
所以,我会将模板更改为:
<svg>
<g>
<ng-container #svgRef></ng-container>
</g>
</svg>
我建议做的是用
<rect ... />
包装部分 SVG 代码(在示例中为 <ng-template>
)并通过 public TemplateRef
公开它,例如:
@Component({
standalone: true,
template: `
<ng-template>
<rect width="200" height="100" x="10" y="10" rx="20" ry="20" fill="blue" />
<ng-template>
`,
schemas: [NO_ERRORS_SCHEMA]
})
export class Rect {
@ViewChild(TemplateRef, { static: true }) rectRef!: TemplateRef<unknown>;
}
然后使用它:
drawElement(drawingElementName:string){
// clear view container
this.svgRef.clear();
const [ el ] = this.registry.filter(r => r.name = drawingElementName);
// embed component
const newComponentRef = this.svgRef.createComponent(el.elementType, { index: 0 });
// embed template ref exposed by created component
this.svgRef.createEmbeddedView(newComponentRef.instance.rectRef, { index: 1 });
// remove component (we needed only its template ref)
this.svgRef.remove(0);
}
我创建了STACKBLITZ来玩