typescript D3.js 组件中的样式不以 angular 2 显示

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/36214546/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-21 03:22:34  来源:igfitidea点击:

Styles in component for D3.js do not show in angular 2

d3.jstypescriptangular

提问by Hongbo Miao

I am using Angular 2 and D3.js. I want to show a red rectangle.

我正在使用 Angular 2 和 D3.js。我想显示一个红色矩形。

It only works if I put styles in the style.cssfile. Check this plunkr

仅当我将样式放入style.css文件时才有效。检查这个 plunkr

When I put my styles in the component styles: [], it does not work. Check this plunkr

当我将样式放入组件时styles: [],它不起作用。检查这个 plunkr

How to let it work when I use the component styles: []? Thanks

当我使用组件时如何让它工作styles: []?谢谢

UPDATE:@micronyks provides a solution, but it makes the styles in the component global, basically no difference with writing in style.cssfile. In this plunkr, it shows style in one component will override another component's styles, so cannot show green and red rectangles.

更新:@micronyks 提供了一个解决方案,但是它使组件中的样式具有全局性,与编写在style.css文件中基本没有区别。在这个 plunkr 中,它显示一个组件中的样式将覆盖另一个组件的样式,因此不能显示绿色和红色矩形。

UPDATE 2:@Günter's way perfectly solve this problem!! Just a remind, for Günter's way: it needs at least Angular beta 10. (My other plunkrs use Angular beta 8) The working demo for green and one red rectangle using Angular beta 12 is here.

更新 2:@Günter 的方法完美地解决了这个问题!!只是提醒一下,对于 Günter 的方式:它至少需要 Angular beta 10。(我的其他 plunkrs 使用 Angular beta 8)使用 Angular beta 12 的绿色和一个红色矩形的工作演示在这里

import {Component} from 'angular2/core'
@Component({
  selector: 'my-app',
  providers: [],
   styles: [`
    /*this does not work*/
    .bar {
      fill: red;
    }
  `],
  template: `
    <div>
      <svg class="chart"></svg>
    </div>
  `,
  directives: []
})
export class App {
  constructor() {}

  ngOnInit() {
    this.draw();
  }

  draw() {
    let data = [{name: 'A', value: 1}];
    let width = 400, height = 200;

    let x = d3.scale.ordinal().rangeRoundBands([0, width]);
    let y = d3.scale.linear().range([height, 0]);

    let chart = d3.select(".chart")
      .attr("width", width)
      .attr("height", height)
      .append("g");

    x.domain(data.map(function(d) { return d.name; }));
    y.domain([0, d3.max(data, function(d) { return d.value; })]);

    chart.selectAll(".bar")
      .data(data)
      .enter().append("rect")
      .attr("class", "bar")
      .attr("x", function(d) { return x(d.name); })
      .attr("y", function(d) { return y(d.value); })
      .attr("height", function(d) { return height - y(d.value); })
      .attr("width", x.rangeBand());
  }
}

回答by Günter Z?chbauer

Update

更新

Angular and SASS agreed on supporting ::ng-deep(instead of >>>or /deep/) a while ago until ::slottedor whatever makes it into browser standards becomes abailable in all browsers.

Angular 和 SASS不久前同意支持::ng-deep(而不是>>>/deep/),直到::slotted或任何使其成为浏览器标准的东西在所有浏览器中都可用。

ViewEncapsulation.Emulated (default)

ViewEncapsulation.Emulated(默认)

That's by design. Angular adds class names unique to components and rewrites the added styles to only apply to the components where they were added.

那是设计使然。Angular 添加了组件独有的类名,并将添加的样式重写为仅适用于添加它们的组件。

D3 generates HTML dynamically without Angulars knowledge and Angular can't apply the classes to make the styles apply on the generated HTML.

D3 在没有 Angulars 知识的情况下动态生成 HTML,Angular 无法应用这些类来使样式应用于生成的 HTML。

If you add the styles at the entry point HTML file, Angular also doesn't rewrite the styles and the added helper classes don't take effect.

如果在入口点 HTML 文件中添加样式,Angular 也不会重写样式,并且添加的辅助类不会生效。

ViewEncapsulation.None

ViewEncapsulation.None

With encapsulation: ViewEncapsulation.NoneAngular doesn't do this rewriting, therefore the result is similar to adding the HTML to the index.html.

随着encapsulation: ViewEncapsulation.None角度不这样做重写,因此结果是类似于添加HTML的index.html

"Shadow-piercing"

《穿影》

Alternatively you can use the recently introduced shadow piercing CSS combinators >>>, /deep/and ::shadow(::shadowis just replaced by a and thus very limited). See also https://stackoverflow.com/a/36225709/217408and the Plunker

或者,您可以使用最近引入的阴影穿透 CSS 组合器>>>, /deep/and ::shadow(::shadow只是被 a 替换,因此非常有限)。另见https://stackoverflow.com/a/36225709/217408Plunker

:host /deep/ div {
  color: red;
}

SASS

SASS

/deep/works fine with SASS but the alias >>>doesn't.

/deep/SASS 工作正常,但别名>>>不行。

The shadow-piersing CSS combinators are rewritten by Angular and they don't need to be supported by the browsers. Chrome supported them for a while but they are deprecated - but as said, that doesn't matter, because Angular rewrites them to use its encapsulation emulation.

穿透阴影的 CSS 组合器由 Angular 重写,它们不需要浏览器支持。Chrome 支持它们一段时间,但它们已被弃用 - 但如上所述,这并不重要,因为 Angular 重写它们以使用其封装仿真。

ViewEncapsulation.Native

ViewEncapsulation.Native

Angular doesn't support any way to style such components from the outside. Only if the browser provides support like CSS variables then these can be used.

Angular 不支持任何方式从外部设置此类组件的样式。只有当浏览器提供像 CSS 变量这样的支持时,才可以使用这些变量。

回答by micronyks

ViewEncapsulationwill fix your problem.

ViewEncapsulation将解决您的问题。

import {Component,ViewEncapsulation} from 'angular2/core'

@Component({
  selector: 'my-app',
  encapsulation: ViewEncapsulation.None,
  providers: [],
   styles: [`
     .bar {
       fill: red;
    }
  `],
  template: `
    <div>
      <svg class="chart"></svg>
    </div>
  `,
  directives: []
})

回答by Micha? Miszczyszyn

View Encapsulation

查看封装

This is because of the view encapsulation in Angular 2. By default, all the HTML and CSS is transformed so that it's only applied locally. In other words, if you add this style in your component's CSS:

这是因为 Angular 2 中的视图封装。默认情况下,所有的 HTML 和 CSS 都会被转换,以便它只在本地应用。换句话说,如果您在组件的 CSS 中添加此样式:

h2 { color: red; }

It will only affect h2 elements inside the component, not every h2 element in your whole app. You can read more about this mechanisms in Angular documentation on View Encapsulation.

它只会影响组件内的 h2 元素,而不是整个应用程序中的每个 h2 元素。您可以在 View Encapsulation 的 Angular 文档中阅读有关此机制的更多信息。

Why does it affect you?

为什么它会影响你?

Angular transforms your styles but since the C3 graph is not yet drawn, it can't transform HTML/SVG too. Because of that, component styles won't match elements inside of C3 graph.

Angular 会转换您的样式,但由于尚未绘制 C3 图形,因此它也无法转换 HTML/SVG。因此,组件样式不会匹配 C3 图形内部的元素。

What should I do?

我该怎么办?

External stylesheet

外部样式表

External stylesheets are not transformed by the View Encapsulation mechanisms, so effectively they will affect your C3 chart (and any other element for that matter).

视图封装机制不会转换外部样式表,因此它们会有效地影响您的 C3 图表(以及任何其他与此相关的元素)。

If you're using Angular CLI, adding external stylesheet is really simple. Edit your angular-cli.jsonfile and inside of appsproperty find stylesarray. Add another stylesheet here:

如果您使用的是 Angular CLI,添加外部样式表非常简单。编辑您的angular-cli.json文件和apps属性查找styles数组内部。在此处添加另一个样式表:

{
    …
    "apps": [
        {
            …
            "styles": [
                "styles.scss",
                "c3.scss" // <---- add this or any other file
            ],
        }
    ],
    …
}

In case you're not using Angular CLI, there must be some way to add external stylesheets. Probably the simplest one is adding another <link …>inside of <head>in your index.htmlfile.

如果您不使用 Angular CLI,则必须有某种方法来添加外部样式表。也许最简单的是增加一个<link …>内部<head>在你的index.html文件中。

ViewEncapsulation.None

ViewEncapsulation.None

Your first option is: Create a component with the chart (and only chart) and turn off View Encapsulation inside of it. It's a good idea to do that also because of obeying the Single Responsibility Principle. Your chart, by design, should be encapsulated in a separate component. Turning of View Encapsulation is as simple as adding another property to your @Componentdecorator:

您的第一个选择是:使用图表(并且仅图表)创建一个组件并关闭其中的 View Encapsulation。由于遵守单一职责原则,这样做也是一个好主意。根据设计,您的图表应该封装在一个单独的组件中。关闭视图封装就像向@Component装饰器添加另一个属性一样简单:

@Component({
    …
    encapsulation: ViewEncapsulation.None
})

/deep/CSS selector

/deep/CSS 选择器

If, for some reason, you don't want to do that, there's another possibility. You can try using /deep/selector inside of your CSS which forces styles down into all child components views. Effectively, this breaks the encapsulation and should affect your C3 chart. So, for example, you can do that in your component's CSS file:

如果出于某种原因,您不想这样做,还有另一种可能性。您可以尝试/deep/在 CSS 中使用选择器,它会将样式强制下放到所有子组件视图中。实际上,这会破坏封装并且应该会影响您的 C3 图表。因此,例如,您可以在组件的 CSS 文件中执行此操作:

/deep/ .c3-chart-arc path {
    stroke: white;
}

Either way, I recommend reading the aforementioned documentation on View Encapsulation in Angular 2in order to understand why this happens and how it works. This feature is supposed to help you write code, not cause troubles :) This article might help you understand how it works: View Encapsulation on blog.thoughtram.io

无论哪种方式,我都建议您阅读上述有关Angular 2中的视图封装的文档,以了解为什么会发生这种情况以及它是如何工作的。此功能旨在帮助您编写代码,而不是造成麻烦:) 这篇文章可能会帮助您了解它的工作原理:在 blog.thoughtram.io 上查看封装

回答by Angel Angel

...then I cannot show one red and one green rectangle... The problem comes back

...然后我不能显示一个红色和一个绿色的矩形...问题又来了

I think it's some override, I do not know how much of this is true, but I think this solves your problem.

我认为这是一些覆盖,我不知道这有多少是真的,但我认为这解决了你的问题。

add in child1-cmp, child1-cmp .barfor example:

加入child1-cmpchild1-cmp .bar例如:

@Component({
  encapsulation: ViewEncapsulation.None,
  selector: 'child1-cmp',
   styles: [`
    child1-cmp .bar {
      fill: red;
    }
  `],
  template: `
    <div>
      <svg class="chart1"></svg>
    </div>
  `,
  directives: []
})

Note: in addition to encapsulation: ViewEncapsulation.None, as mentioned by micronyks.

注意:除此之外encapsulation: ViewEncapsulation.None,正如micronyks所提到的。

Test

测试

Plunker

Plunker



or this:

或这个:

@Component({
  selector: 'my-app',
  directives: [Child1Cmp, Child2Cmp],
   encapsulation: ViewEncapsulation.None,
   styles: [`
    child1-cmp .bar {
      fill: red;
    }

    child2-cmp .bar {
      fill: yellow;
    }
  `],
   ..//


@Component({
  //encapsulation: ViewEncapsulation.None,
  selector: 'child1-cmp',
  template: `
    <div>
      <svg class="chart1"></svg>
    </div>
  `,
  directives: []
})


@Component({
  //encapsulation: ViewEncapsulation.None,
  selector: 'child2-cmp',
  template: `
    <div>
      <svg class="chart2"></svg>
    </div>
  `,
  directives: []
})

Test

测试

Plunker

Plunker



or this using class .chart1, .chart2, for example if you want.

或使用 class .chart1, .chart2,例如,如果您愿意。

@Component({
  selector: 'my-app',
  directives: [Child1Cmp, Child2Cmp],
   encapsulation: ViewEncapsulation.None,
   styles: [`
    .chart1 .bar {
      fill: red;
    }

    .chart2 .bar {
      fill: yellow;
    }
  `],
   ..//

Test

测试

Plunker

Plunker

回答by maia

I found that * /deep/ .my-element-classworks, but for some reason, ONLY if the svg parent element is present in the html template (not when the svg parent element is created on the fly by d3).

我发现这* /deep/ .my-element-class可行,但出于某种原因,仅当 svg 父元素存在于 html 模板中时(不是当 svg 父元素由 d3 动态创建时)。

For instance, the following situation would work:

例如,以下情况会起作用:

mycomponent.component.html

mycomponent.component.html

<svg id="mygraph"></svg> <!-- IMPORTANT!! -->

mycomponent.component.css

mycomponent.component.css

* /deep/ .my-element-class {
  /* ... desired styles */
}

mycomponent.component.ts

mycomponent.component.ts

d3.select("svg#mygraph").append("circle").classed("my-element-class", true)
 ...