使用 SVG 模板注入动态组件

是否可以注入作为子 svg 元素的动态组件? 例如,我有一个主要组件 (CanvasComponent) ,它的模板是这样的 是否可以注入作为子 svg 元素的动态组件? 比如我有一个主组件(CanvasComponent),它的模板是这样的 <svg width="400" height="400"> <ng-template appCanvasAnchor></ng-template> </svg> ng-template 是用于动态注入组件的锚点https://angular.io/guide/dynamic-component-loader 动态(SquareComponent)已经有了这个模板 <svg:rect width="100" height="100" style="fill:red" /> 现在,由于动态组件添加到 DOM 的方式,当我的 Square 组件添加到 DOM 时,它将被包含在 div 元素中,如下所示。 <svg width="400" height="400"> <div app-square> <rect width="100" height="100" style="fill:red" /> </div> </svg> 理论上,一切都工作得很好,除了这是 SVG,因此我的方块不会渲染,因为它有未知的标记(div)。这里的问题是,我可以以某种方式改变注入器使用的元素,以便它不使用 div,而是使用 svg 知道像 g 这样的元素吗? 不确定模板,但可以在一些解决方法的帮助下通过内容投影动态注入 svg-s。 主要的解决方法是找到一种方法来删除组件的宿主元素,这可以通过创建如下指令来处理,该指令将处理某些元素的“展开”。如下所示,该指令执行类似于 js 中的展开运算符的操作,它获取其所附加的元素的所有子元素并将它们展开到父元素的级别 @Directive({ selector: '[appRemoveHost]', standalone: true, }) export class RemoveHostDirective { constructor(private el: ElementRef) {} //wait for the component to render completely ngOnInit() { var nativeElement: HTMLElement = this.el.nativeElement, parentElement: HTMLElement = nativeElement.parentElement; // move all children out of the element while (nativeElement.firstChild) { parentElement.insertBefore(nativeElement.firstChild, nativeElement); } // remove the empty element(the host) parentElement.removeChild(nativeElement); } } 感谢这个问题和答案删除由角度组件创建的主机 HTML 元素选择器 之后,您只需为要使用的 SVG 元素创建包装器组件即可。 示例画布组件看起来像这样 @Component({ selector: 'app-canvas', template: `<svg width="400" height="400"> <ng-content></ng-content> </svg>`, standalone: true, imports: [CommonModule], }) export class CanvasComponent {} 自定义 SVG 元素可以如下所示 @Component({ selector: 'app-custom-rect,[app-custom-rect]', template: `<svg appRemoveHost> <rect [attr.x]="x" [attr.y]="y" [attr.width]="width" [attr.height]="height" style="{{ style }}" /> </svg>`, standalone: true, imports: [CommonModule, RemoveHostDirective], }) export class CustomRectComponent { @Input() style = ''; @Input() x = ''; @Input() y = ''; @Input() width = ''; @Input() height = ''; } 这里值得一提的是,否则我们需要创建 svg 包装元素 Only void and foreign elements can be self-closed "rect" 作为 rect 元素只能存在于 svg-s 中。 正如此处所示,我们正在使用 appRemoveHost,这要归功于当我们的组件被渲染时, 包装器将被删除。 最后,在我们想要使用画布的地方,我们应该执行以下操作 <app-canvas> <app-custom-rect appRemoveHost [y]="'50'" [x]="'0'" [width]="'100'" [height]="'100'" [style]="'fill:red'" ></app-custom-rect> <app-canvas/> 这里我们再次需要使用 appRemoveHost 指令来删除 rect 组件的剩余包装。 在这里您可以找到工作 Stackblitz 是否可以注入作为子 svg 元素的动态组件? 是的,当然。 Angular 已经支持这一点好几年了,但我不确定我是否已经看到了这一点的详细记录。 当你创建 Angular 组件时,你的选择器可以是很多东西。它不一定是一个标签。我们将利用这一点来使用属性。 首先,让我们构建托管 SVG 的主要组件: import { Component } from '@angular/core'; @Component({ selector: 'app-main', templateUrl: './main.component.html', styleUrls: ['./main.component.css'], }) export class MainComponent {} 和 HTML: <svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"> <svg:g house></svg:g> </svg> 正如您可能已经猜到的,诀窍就在这里:<svg:g house></svg:g>。我们创建一个组,它不会渲染任何内容。但我们给它添加了一个属性house。 然后要在那里“注入”组件,我们可以让组件选择器以带有组的 svg 标签和 house 属性为目标: import { Component } from '@angular/core'; @Component({ selector: 'svg:g[house]', templateUrl: './house.component.html', styleUrls: ['./house.component.css'], }) export class HouseComponent {} 最后一块拼图几乎就是 SVG:要注入的部分 <svg:polygon points="25,10 40,30 10,30" style="fill:rgb(0,0,255);" /> <svg:rect width="30" height="30" x="10" y="30" style="fill:rgb(0,0,255);" /> 如果我们查看渲染的 HTML: <app-main _ngcontent-rcx-c227="" _nghost-rcx-c226="" ><svg _ngcontent-rcx-c226="" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" > <g _ngcontent-rcx-c226="" house="" _nghost-rcx-c217=""> <polygon _ngcontent-rcx-c217="" points="25,10 40,30 10,30" style="fill: rgb(0,0,255);" ></polygon> <rect _ngcontent-rcx-c217="" width="30" height="30" x="10" y="30" style="fill: rgb(0,0,255);" ></rect> </g></svg ></app-main> 没有我们内部组件的任何痕迹。当然,您可以根据需要拥有任意数量和嵌套的数量。您还可以通过将数据作为输入传递来参数化它们,就像使用任何其他组件或注入服务一样。 这是 Stackblitz 上的 现场演示。 jscw 使用本机 JavaScript Web 组件可能会更容易 <svg-floorplan> 处理其innerHTML 并在shadowDOM中生成<SVG> 基于 HTMLUnknownElements <room>(打造出色的语义 HTML) 它声明了正确的 SVG 的 x,y,width,height,fill 属性 <rect> 基于 <rect> 标签可以定位在中间 innerHTML 中任何剩余的 SVG 元素都被移动到新的<SVG> 您的 JavaScript 技能可以增加更多... <svg-floorplan viewBox="0 0 300 100"> <style>text{fill:gold}</style> <room rect="0 0 200 50">living</room> <room rect="200 0 100 100 blue">kitchen</room> <room rect="0 50 100 50">bedroom</room> <room rect="100 50 100 50 green">bathroom</room> <circle fill="red" cx="25" cy="25" r="10"></circle> </svg-floorplan> 创造: <svg-floorplan viewBox="0 0 300 100"> <style>text{fill:gold}</style> <room rect="0 0 200 50">living</room> <room rect="200 0 100 100 blue">kitchen</room> <room rect="0 50 100 50">bedroom</room> <room rect="100 50 100 50 green">bathroom</room> <circle fill="red" cx="25" cy="25" r="10"></circle> </svg-floorplan> <script> customElements.define("svg-floorplan", class extends HTMLElement { connectedCallback() { setTimeout(() => { // make sure innerHTML is parsed let svg = `<svg viewBox="${this.getAttribute("viewBox")}">`; svg += `<rect x="0" y="0" width="100%" height="100%" fill="grey"/>`; this.querySelectorAll('room[rect]').forEach(rm => { let [x, y, width, height, fill="grey"] = rm.getAttribute("rect").split(" "); svg += `<rect x="${x}" y="${y}" width="${width}" height="${height}" stroke="black" fill="${fill}"/>`; let label = rm.innerHTML; svg += `<path id="${label}" pathLength="100" d="M${x} ${~~y+height/2}h${width}" stroke="none"></path> <text><textPath href="#${label}" startoffset="50" dominant-baseline="middle" text-anchor="middle">${label}</textPath></text>`; rm.remove(); }); svg += `</svg>`; this.attachShadow({mode:"open"}).innerHTML = svg; this.shadowRoot.querySelector("svg") .insertAdjacentHTML("beforeend",this.innerHTML) }) } }) </script> 文档可能会帮助您: 您可以在 Angular 应用程序中使用 SVG 文件作为模板。当您使用 SVG 作为模板时,您可以像使用 HTML 模板一样使用指令和绑定。使用这些功能动态生成交互式图形。 我建议你创建一个可以以 Angular 方式控制的 SVG 组件,对于动态模板显示,你可以做的是: <div class="container" *appCanvasAnchor> </div> .container { width: 400px; height: 400px; svg { width: 100%; height: 100%; } }

回答 4 投票 0

训练 DL 模型时,本地集合点正在中止,状态为:OUT_OF_RANGE:序列结束

我正在创建一个植物病害识别模型。我有一个包含 38 种疾病的数据集,每种疾病有大约 2000 张图像。但是在训练模型时,由于某些原因,某些时期会被跳过

回答 1 投票 0

更新$slots获取的子组件中的数据

我正在使用 VueJS 3.4.25 和选项 API。 所以我将这两个组件定义如下: // 组件A ... ... ...</desc> <question vote="0"> <p>我正在使用 VueJS 3.4.25 和选项 API。</p> <p>所以我将这两个组件定义如下:</p> <pre><code>// ComponentA &lt;template&gt; ... &lt;slot&gt;&lt;/slot&gt; ... &lt;/template&gt; &lt;script&gt; export default { ... methods: { fireComponentAMethod() { const slotNode = this.$slots.default()[0]; slotNode.type.methods.fireComponentBMethod(); }, }, } &lt;/script&gt; </code></pre> <pre><code>// ComponentB &lt;template&gt; ... isValueSet: {{ isValueSet }} ... &lt;/template&gt; &lt;script&gt; export default { ... data() { return { isValueSet: false, }; }, methods: { fireComponentBMethod() { console.log(&#34;I just fired fireComponentBMethod&#34;); this.isValueSet = true; console.log(this.isValueSet); }, }, } &lt;/script&gt; </code></pre> <p>Ans 在其他地方我以这种方式设置组件:</p> <pre><code>// Some absolutely unrelated component &lt;ComponentA&gt; &lt;ComponentB /&gt; &lt;/ComponentA&gt; </code></pre> <p>这样做的原因是我的目标是提高代码的可重用性,因此有时是<pre><code>ComponentB</code></pre>,有时是<pre><code>ComponentC</code></pre>和<pre><code>ComponentDoubleD</code></pre>内的<pre><code>ComponentA</code></pre>。</p> <p>当 <pre><code>fireComponentAMethod</code></pre> 被触发时,会观察到该问题。它确实会触发 <pre><code>fireComponentBMethod</code></pre> 并且在控制台中我确实看到了</p> <pre><code>I just fired fireComponentBMethod true </code></pre> <p>但变化并没有反映在<pre><code>ComponentB</code></pre>模板中,它一直停留在页面上<pre><code>isValueSet: false</code></pre>。</p> <p>我尝试使用 <pre><code>$refs</code></pre> 来访问孩子们,但我想因为他们在插槽中,所以它不起作用。</p> </question> <answer tick="false" vote="0"> <p>我相信,在大多数情况下,从父组件调用子组件方法是不行的,即使您想实现高水平的可重用性。</p> <p>如果您的用例是:</p> <pre><code>&lt;ComponentA&gt; &lt;ComponentB /&gt; &lt;/ComponentA&gt; </code></pre> <p>其中 <pre><code>&lt;ComponentB /&gt;</code></pre> 可以替换为 <pre><code>&lt;ComponentC /&gt;</code></pre> 或 <pre><code>&lt;ComponentD /&gt;</code></pre>,并且它始终位于 <pre><code>&lt;ComponentA /&gt;</code></pre> 内。那么你想要实现的就是所谓的<pre><code>COMPOUND COMPONENT</code></pre>模式。</p> <p>引用 alex vipond <a href="https://rethinking-reusability-in-vue.alexvipond.dev/" rel="nofollow noreferrer">重新思考 vue 的可重用性</a>:</p> <blockquote> <p>在一组复合组件中,有一个父组件管理大部分或全部状态,并且有一些后代组件插入父组件。在内部,这些后代修改并观察父级的状态,准备对其他后代所做的修改做出反应。</p> </blockquote> <p>但最重要的一点是:</p> <blockquote> <p>此外,子组件不能在父组件之外使用。如果没有父母的反应状态,后代就会崩溃</p> </blockquote> <p>现在,我看到很多组件库确实使用了这种模式。例如,Headless UI 的<a href="https://github.com/tailwindlabs/headlessui/blob/main/packages/%40headlessui-vue/src/components/menu/menu.ts" rel="nofollow noreferrer">这个菜单组件</a>确实使用了这种模式。父级管理几乎所有状态并通过大量使用<a href="https://vuejs.org/guide/components/slots.html#scoped-slots" rel="nofollow noreferrer">范围插槽</a>和<a href="https://vuejs.org/guide/components/provide-inject" rel="nofollow noreferrer">提供和注入</a>将其提供给子级。</p> <p>此外,Vue.js 官方文档也有一个类似的部分模式,称为 <a href="https://vuejs.org/guide/components/slots.html#renderless-components" rel="nofollow noreferrer">Renderless Components</a>,这是许多 UI 组件库用来实现可重用性的类似模式。</p> <p>因此,对于您的用例,您可以利用<a href="https://vuejs.org/guide/components/provide-inject" rel="nofollow noreferrer">提供和注入</a>来实现类似的可重用性。</p> <p>这个例子将使用<a href="https://vuejs.org/guide/components/provide-inject" rel="nofollow noreferrer">提供和注入</a>,但您也可以使用<a href="https://vuejs.org/guide/components/slots.html#scoped-slots" rel="nofollow noreferrer">作用域插槽</a>来实现类似的结果:</p> <pre><code>// ComponentA.vue &lt;script setup&gt; import { provide } from &#39;vue&#39; function fireComponentAMethod() { alert(&#39;fire&#39;) } provide(&#39;componentAMethod&#39;, fireComponentAMethod) &lt;/script&gt; &lt;template&gt; &lt;slot&gt;&lt;/slot&gt; &lt;/template&gt; </code></pre> <p>和<pre><code>ComponentB</code></pre>:</p> <pre><code>// ComponentB.vue &lt;script setup&gt; import { inject } from &#39;vue&#39; const componentAMethod = inject(&#39;componentAMethod&#39;) &lt;/script&gt; &lt;template v-slot=&#34;slotProps&#34;&gt; &lt;button @click=&#34;componentAMethod&#34;&gt;Click Me&lt;/button&gt; &lt;/template&gt; </code></pre> <p>这是一个<a href="https://play.vuejs.org/#eNp9Uk1vwjAM/StRLmUSo4ftxAoaIA6bxIa2HXthwUCgJFHiMiTEf5/d8lE+T0nsZ/u9+G1kx7nGKgfZlElQXjsUATB37dTopbMeRc/SacBgR0y8XYqoER9DXBq9XGK7l9juHpvE5SAaQQ+EpctGCPQSIjl2Lt7VSFesHkNmsZVKPobeupBKEZeFFU4USOJKW1mXGJQ1Ez1tzIM1JHXDNalUVKMz8J8OtTXUrSmKDOdGWWb/3osY+hzq+7iagVpcic/DmmOpHHoI4FeQykMOR34KWKb73x+wpvshubTjPCP0neQXBJvlzLGEdXMzJtoVXMH2rViCNtOf0F8jmLAXxUQZuS3wqaRF8Hfdkn6k+9R4LupSs6VfPF37bcdshPN2pccgtjsb8OZ525PcKJ4nJtoXFMp2A8CZHdceSgojooW1iCHRA03mwl3DWsQrqxZF9au9qO6ezdhAbQLwcemWU8ve06nNHBReyCSzBRTnVEVrh7+i4ibfq6YvRfzmiPSVryrTakGA86aE63FKDCCJS/CpWEFqt/8l/mRQ" rel="nofollow noreferrer">简单的 vue.js 游乐场</a>,它使用<a href="https://vuejs.org/guide/components/slots.html#scoped-slots" rel="nofollow noreferrer">作用域插槽</a>和<a href="https://vuejs.org/guide/components/provide-inject" rel="nofollow noreferrer">提供和注入</a>来实现类似的结果。</p> </answer> </body></html>

回答 0 投票 0

出口无法工作 - 未找到页面 - React 路由器,Vite 5

使用Outlet进行react路由,在使用vite构建或预览后出现页面未找到错误(在开发环境中工作正常) 根.tsx 导出默认函数 Root() { 返回...

回答 1 投票 0

将 java.util.logging 级别设置为 FINER,但不会打印“log.fine()”,仅打印“log.severe()”

我正在尝试在 slf4j 过滤器中使用 java.util.logging,因为我无法在那里使用 slf4j 记录器。 我正在使用 Java 11 并使用 Maven 进行构建。 由于某种原因,我可以将 SEVERE、INFO 和 WARNING 日志发送到

回答 1 投票 0

停止 Codesandbox 在文件更改时自动更新预览

如何让 Codesandbox 在我打字时停止更新浏览器预览? 我在 VS Code 中关闭了自动保存,但 Codesandbox 仍然会立即更新预览窗格,一直显示很长的时间...

回答 3 投票 0

UITextView 换行未检测到

我有这个 Uiview 可以用行号表示,效果足够好,但是当一行环绕行号时,不会检测到这一点。我使用了“enumerateLineFragments”,但使用...

回答 1 投票 0

数组公式从第二个相关行返回数据,无法获取第一行

我想从源工作表中复制,从相关行中选择列 (h,f,e,g,k)(相关行具有与目标工作表 A1/“标题”匹配的 B 列条目) 我正在使用的公式...

回答 1 投票 0

将值分组到单列而不是多列中

我有包含组变量的多列数据集。我想将值分组到单列中 我有这样的数据集 VAR1 VAR2 分数 男性 LOC1 20 男性 LOC2 30 男性 LOC3 40 女性 LOC4 50 ...

回答 1 投票 0

Composer 无法在 Windows 上工作,给出 [Composer\Exception\NoSslException] 错误

我正在尝试在 Windows 10 上安装 Laravel。我安装了 Composer 来安装 Laravel,但它给了我以下错误。 [Composer\Exception\NoSslException] openssl 扩展名是 需要 S...

回答 3 投票 0

缺少以下扩展!请在 php.ini 中启用 PHP 扩展

我正在尝试安装 phpMyFAQ,但收到错误消息 缺少以下扩展!请在 php.ini 中启用 PHP 扩展。 谁能帮我在哪里可以找到...

回答 2 投票 0

获取 Quartz.NET 2.0 中的所有作业

我已经在服务器上设置了 AdoJobStore,并且我的所有作业都运行良好。现在我正在编写一个远程客户端来管理我的所有工作。 安排新工作很简单,但我看不到...

回答 5 投票 0

在表单之间传递值

我有几个表格(我没有使用formwizard) 我想根据以前的形式的价值做出决定。 例如: - 如果 form1.field 具有特定值,则禁用 form2.field - 转移...

回答 1 投票 0

如何在 Angular 中将行转换为列以及将列转换为行

只需要您的帮助和想法,了解如何以角度将行转换为列,将列转换为行。 [ {“playerId”:“1001”,“playerName”:“勒布朗·詹姆斯”,“游戏&...

回答 1 投票 0

在JS中获取名字和姓氏的首字母

我想使用现代 JavaScript 语法检索一个人名字和姓氏的首字母。目前,我可以检索名字的第一个字母和第一个字母...

回答 1 投票 0

计算股票投资组合的平均评级

0 A 乙 C 1 股票 评分 投资价值 2 库存A 2 500 3 库存B 3 800 4 库存C 1 100 5 库存D 3 900 6 库存E 3 400 7 8 平均评分 ?? 9 我有一个由不同股票组成的投资组合...

回答 1 投票 0

在 C++ 中出现缺少 vtable 错误,导致“clang: error: linker command failed with exit code 1”

我正在尝试研究c++中的接口和类。运行代码时,我收到缺少 vtable 的错误。我的完整代码是: #包括 IGPS 类{ 民众: 虚拟浮动

回答 1 投票 0

使用 Salesforce Apex 中的 RESTlet 集成 NetSuite 时出现无效登录尝试错误

我正在努力将 NetSuite 与 Salesforce 连接起来,以使用 RESTlet 脚本和 OAuth 1 进行授权在 NetSuite 中创建客户记录。虽然我可以使用 POSTMAN 创建记录,但尝试...

回答 2 投票 0

如何在Power-BI DAX中计算多个类别的平均值?

我有一个包含以下列的表格: 行业表 Industry_ID 分数 1 2 1 3 2 2 2 ...

回答 2 投票 0

从表中删除多行

当前运行的是Excel 2013。我的电子表格最近变成了一个表格,它有几千行数据。在我按日期范围过滤然后删除某些行之前,我正在使用 Fi...

回答 3 投票 0

© www.soinside.com 2019 - 2024. All rights reserved.