D3.js组件中的样式不显示在角度2中

时间:2016-03-25 05:28:33

标签: d3.js typescript angular

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

仅当我将样式放在 style.css 文件中时才有效。 查看this plunkr

当我将我的样式放在 styles: [] 组件中时,它不起作用。查看this plunkr

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

UPDATE: @micronyks提供了一个解决方案,但它使组件中的样式全局化,与 style.css 文件中的写入基本没有区别。在this plunkr中,它显示一个组件中的样式将覆盖另一个组件的样式,因此无法显示绿色和红色矩形。

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

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());
  }
}

6 个答案:

答案 0 :(得分:41)

ViewEncapsulation.Emulated(默认)

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

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

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

<强> ViewEncapsulation.None

使用encapsulation: ViewEncapsulation.None Angular不会执行此重写,因此结果类似于将HTML添加到index.html

<强> “影子刺穿”

或者你可以使用最近推出的阴影穿孔CSS组合器>>>/deep/::shadow::shadow刚刚被取代,因此非常有限)。另请参阅https://stackoverflow.com/a/36225709/217408Plunker

:host / deep / div {      红色;    }

<强> SASS

/deep/适用于SASS但别名>>>没有。

阴影匹配CSS组合器由Angular重写,它们不需要浏览器支持。 Chrome支持它们一段时间但它们已被弃用 - 但正如所说,这无关紧要,因为Angular会重写它们以使用其封装模拟。

<强> ViewEncapsulation.Native

Angular不支持从外部设置此类组件的任何方式。只有当浏览器提供CSS变量等支持时,才能使用它们。

答案 1 :(得分:18)

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: []
})

答案 2 :(得分:7)

查看封装

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

h2 { color: red; }

它只会影响组件中的 h2元素,而不会影响整个应用中的每个h2元素。您可以在Angular documentation on View Encapsulation中了解有关此机制的更多信息。

为什么会对您产生影响?

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

我该怎么办?

外部样式表

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

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

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

如果您不使用Angular CLI,必须有一些方法来添加外部样式表。可能最简单的一个是在<link …>文件中的<head>内添加另一个index.html

ViewEncapsulation.None

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

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

/deep/ CSS选择器

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

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

无论哪种方式,我建议您阅读View Encapsulation in Angular 2上的上述文档,以了解其发生的原因及其工作原理。这个功能应该可以帮助你编写代码,而不会引起麻烦:) 本文可能会帮助您了解其工作原理:View Encapsulation on blog.thoughtram.io

答案 3 :(得分:2)

答案 4 :(得分:1)

  

...然后我无法显示一个红色和一个绿色矩形......问题   回来了

我认为它有些超越,我不知道这有多少是真的,但我认为这解决了你的问题。

添加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: []
})

注意:除了encapsulation: ViewEncapsulation.None之外,micronyks提及。

测试

Plunker

或者这个:

@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: []
})

测试

Plunker

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

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

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

测试

Plunker

答案 5 :(得分:0)

我发现* /deep/ .my-element-class有效,但由于某种原因,只有在html模板中存在svg父元素时才会出现(而不是在d3时动态创建svg父元素时)。

例如,以下情况可行:

mycomponent.component.html

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

mycomponent.component.css

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

mycomponent.component.ts

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