【问题标题】:Angular 2 - How to have an `svg` in app.component and a `circle` as a child component?Angular 2 - 如何在 app.component 中有一个`svg` 和一个`circle` 作为子组件?
【发布时间】:2018-02-01 10:09:18
【问题描述】:

所以我想使用 Angular 开发一个吃豆人游戏,我想为此使用 SVG,我想创建一个嵌入 pacman.componentboard.component

board.component 将有一个 <svg></svg>pacman.component 将有一个 <circle></circle> 但 Angular 在我的 pacman.component 中抛出此错误:

[Angular] 'circle' 不是已知元素:

  1. 如果“circle”是一个 Angular 组件,则验证它是该模块的一部分。
  2. 要允许任何元素将“NO_ERRORS_SCHEMA”添加到此组件的“@NgModule.schemas”。

修复这些错误后,我最终得到了这个 SVG

  <svg _ngcontent-c0="" width="100" height="100">
    <app-pacman _ngcontent-c0="" _nghost-c1="">
      <circle _ngcontent-c1="" fill="yellow" r="25" cx="10" cy="10"></circle>
    </app-pacman>
  </svg>

现在唯一的问题是 angular 用 &lt;app-pacman&gt;&lt;/app-pacman&gt; 包裹了 pacman.component,这使得 circle 不起作用。

只是想知道 Angular 的做法是什么?我不想将整个 svg 代码 (svg, circles, paths, etc...) 放在一个组件中。

谢谢。

编辑:

board.component.html:

<svg [attr.width]="width" [attr.height]="height">
  <app-pacman></app-pacman>
</svg>

pacman.component.html:

<circle [attr.cx]="cx" [attr.cy]="cy" r="25" fill="yellow"></circle>

【问题讨论】:

  • 贴出你的组件类代码
  • 请发布两个组件模板

标签: angular svg


【解决方案1】:

我相信这篇精彩文章中描述的问题的答案:https://teropa.info/blog/2016/12/12/graphics-in-angular-2.html#avoiding-element-selectors-for-components

简而言之,您需要将子组件用作属性而不是元素(您可以这样做,因为@Component 装饰器派生自@Directive)。 应用到您的案例中,它看起来像这样:

在 board.component.html 中:

<svg [attr.width]="width" [attr.height]="height">
    <svg:g app-pacman />
</svg>

在 pacman.component.ts 中:

@Component({
    selector: '[app-pacman]',
    templateUrl: ...
})
...

【讨论】:

  • 是的!就是这样。
  • 请注意,选择器在括号中,因此'[app-pacman]' 与普通的'app-pacman' 不同。
【解决方案2】:

我想你会想做这样的事情:

import { Component } from '@angular/core';

@Component({
    selector: 'svg-component',
    template: `
        <svg>
            <ng-content></ng-content>
        </svg>
    `
})
export class SvgComponent {}

import { Component } from '@angular/core';

@Component({
    selector: 'circle-component',
    template: `
        <ng-container>
            <circle></circle>
        </ng-container>
    `
})
export class CircleComponent {}

【讨论】:

  • 但是如果没有 &lt;circle-component&gt;&lt;/circle-component&gt; 包装器,我如何将 CircleComponent 放在 SvgComponent 中?
  • 你试过了吗?这就是 ng-content ng-container 语法的用途。
  • 是的,我收到 [Angular] &lt;ng-content&gt; element cannot have content.[Angular] &lt;ng-content&gt; element cannot have content. 错误。我试着做:&lt;ng-content&gt;&lt;app-pacman&gt;&lt;/app-pacman&gt;&lt;/ng-content&gt;&lt;ng-content&gt;&lt;circle [attr.cx]="cx" [attr.cy]="cy" r="25" fill="yellow"&gt;&lt;/circle&gt;&lt;/ng-content&gt;
  • 我的错,我切换了ng-contentng-container。我尝试过这样做:&lt;svg [attr.width]="width" [attr.height]="height"&gt;&lt;circle-component&gt;&lt;/circle-component&gt;&lt;ng-content&gt;&lt;/ng-content&gt;&lt;/svg&gt;&lt;ng-container&gt;&lt;circle [attr.cx]="cx" [attr.cy]="cy" r="25" fill="yellow"&gt;&lt;/circle&gt;&lt;/ng-container&gt;,但 Angular 仍然添加了 &lt;circle-component&gt;&lt;/circle-component&gt;。我需要通过嵌入来执行此操作吗?
  • 这是您要查找的内容:plnkr.co/edit/m8PX2UizgmNL2oUdMxhE?p=preview?
【解决方案3】:

SVG 命名空间非常严格。我认为如果 svg 包含未知元素,浏览器会直接拒绝它。这是将 svg 直接注入 DOM 的原因之一,因为原始标记相对(但仍然不是非常)比注入其他类型的标记更安全。我使用 svg 的角度很多,但想想看,我认为我从来没有尝试过将它们的部分分成不同的角度组件。您可以尝试为您的组件使用不同的选择器,例如应用于常规 svg 元素的类或属性选择器。这可能行得通。

我知道指令可以正常工作。几乎所有 my 和元素都有相关的指令。我会尝试使用指令来完成您所需要的 - 它们每个都可以为其主机保存实例数据/属性,类似于组件,唯一的区别是视图全部封装在一个父组件中。您可以使用依赖注入将主机/父组件注入所有子指令实例,或使用@ViewChildren 查询所有子指令实例并从组件中操作它们。

如果需要将元素任意组合在一起,可以使用svg group元素

    <g> ... </g> 

或者你可以使用 Angular 的“隐形”容器,

  <ng-container>...</ng-container> 

如果您需要做的只是遍历某个列表或应用 ngIf 语句等。

【讨论】:

  • 浏览器不会拒绝 SVG,除非它作为 XML 提供,在这种情况下 XML 解析器可能会拒绝它。浏览器(根据 SVG 规范)不应显示 SVG 命名空间中的未知元素或作为已知 SVG 元素子级的未知元素(在任何命名空间中)。
  • 很高兴知道。我猜角度/打字稿编译器会拒绝它们。似乎未知元素破坏了命名空间。
【解决方案4】:

我认为编译器错误[Angular] 'circle' is not a known element 是重点。只需将svg 前缀添加到circle

<div [ngSwitch]="prop?.type">
    <app-svg-circle *ngSwitchCase="'circle'" [props]="prop"></app-svg-circle>
    <svg:path *ngSwitchCase="'path'" prop="prop"></svg:path>
</div>


@Component({
    selector: 'app-svg-base',
    template: `
            <svg:circle ${SvgBaseComponent.Bindings}></svg:circle>
    `
    })
    export class SvgBaseComponent {
      @Input()
      public props;
      public static readonly Bindings = '[attr.x]="props?.x" [attr.y]="props?.y" [attr.stroke]="props?.stroke"'

    }


@Component({
    selector: 'app-svg-circle',
    template: `
            <svg:circle ${SvgBaseComponent.Bindings}></svg:circle>
    `
    })
    export class SvgCircleComponent extends SvgBaseComponent { }

【讨论】:

    猜你喜欢
    • 2019-03-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-16
    • 2017-12-08
    • 1970-01-01
    相关资源
    最近更新 更多