在没有宿主元素容器的情况下渲染嵌套组件 - 将 SVG 部分分成不同的组件
Posted
技术标签:
【中文标题】在没有宿主元素容器的情况下渲染嵌套组件 - 将 SVG 部分分成不同的组件【英文标题】:Render nested components without host element container - Separate SVG parts into Different components 【发布时间】:2020-10-18 20:37:08 【问题描述】:我有一个带有 SVG 元素的组件,我试图将该 SVG 的各个部分分成不同的组件。 嵌套组件需要从父组件动态创建,这是因为我从一个 json 文件构建整个 SVG 图形,该文件确定需要添加哪些嵌套组件(SVG 嵌套形状)。
为了动态创建组件,我使用了 ComponentFactoryResolver 和 ViewContainerRef 来自@angular/core
@Component(
selector: 'skick-player',
templateUrl: './player.component.html',
styleUrls: ['./player.component.scss'],
)
export class PlayerComponent implements OnInit, AfterViewInit
@ViewChild('svgContainer', read: ViewContainerRef ) container;
constructor( private resolver: ComponentFactoryResolver)
performFrame()
....
//Add nested component
const factory = this.resolver.resolveComponentFactory(
BackDropItemComponent
);
const componentRef = this.container.createComponent(factory);
componentRef.instance.imagePath = objectUrl;
);
问题在于 Angular 将嵌套组件包裹在一个 div 中:
<div _nghost-qon-c42="" skick-back-drop-item="" class="ng-star-inserted">
由于创建了特殊的元素标签,因此它不会被渲染。如果该 div 元素被移除,它会正确呈现嵌套的 SVG。
我知道我可以将嵌套组件渲染为指令,它会起作用,如下所示:
<svg>
<svg:g skick-back-drop-item />
</svg>
但在我的用例中,控制器需要从父组件动态呈现,因此这种方法对我不起作用。
也许有办法以编程方式从父组件呈现(添加嵌套控制器)作为指令(请记住嵌套组件具有@input 属性)?
或
是否可以有不可见的组件容器?在没有任何容器的情况下渲染嵌套组件的内容?
父模板:
<div class="patch-overlay" cdkDrag>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:svgjs="http://svgjs.dev/svgjs" >
<<ng-container #svgContainer></ng-container>>
</svg>
</div>
嵌套组件模板(示例):
<svg >
<rect [attr.width]="width" style="fill:rgb(0,0,255);stroke-width:3;stroke:rgb(0,0,0)" />
</svg>
【问题讨论】:
stackblitz.com/edit/… 这次请检查这个例子 Angular 没有将程序创建的组件包装在 div 中 @hanan,谢谢,它将它包装在[
和]
包围:selector: '[skick-back-drop-item]',
你可以应用到任何html标签
【参考方案1】:
我已经尝试过你正在做的事情。我的错误包括构建专门的 FormGroup 组件(不要那样做)。最近,我使用ControlValueAccessor 构建了一个组件,它运行良好,符合我的目的。
我还没有使用ng-template
及其相关功能构建任何东西,例如ngTemplateOutlet
。但是,我怀疑这可能会对您有所帮助。 ng-template
在 DOM 中被移开,这正是您要寻找的。p>
这是 Angular 大学的explanation。我还发现 Netanel Basel 的 info 很棒。
如果您想尝试 CVA 路线,上周我刚刚完成了一个项目的重新编码,并在这里对 SO 进行了大量研究。发现了一个涉及我想做的事情的问题,然后回过头来写了一个对我有用的new answer。看看吧,它可能会给你你需要的东西。
【讨论】:
谢谢@Andrew。 ng-template 在某些情况下从 DOM 中删除,例如在实现 if/else 场景时,但是在从控制器动态注入组件时添加了一个新的 div 容器作为包装器。所以,不幸的是,这种方法对我不起作用. :(【参考方案2】:由于这在谷歌的第一页上显示为最新的问题,这里的解决方法似乎在所有情况下都有效:使用显示内容。
@Component(
selector: 'app-my-component',
templateUrl: './my-component.component.html',
styleUrls: ['./my-component.component.sass'],
host:
style: "display: contents"
)
export class MyComponent
这通过告诉浏览器表现得好像宿主元素根本不存在一样起作用;如果您检查元素,它仍然是 html 的一部分,但它不会成为任何渲染/大小/位置考虑的一部分。 附言这确实比在 html 中完全不包含它有一个优势,它仍然是 CSS 的可选 html 元素
【讨论】:
以上是关于在没有宿主元素容器的情况下渲染嵌套组件 - 将 SVG 部分分成不同的组件的主要内容,如果未能解决你的问题,请参考以下文章