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

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

它只适用于style.css文件中的样式。 检查这个plunkr

当我把我的样式在组件styles: [] ,它不起作用。 检查这个plunkr

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

更新: @micronyks提供了一个解决scheme,但它使全局组件中的样式,在style.css文件中写入基本没有区别。 在这个plunkr中 ,它显示一个组件中的样式会覆盖另一个组件的样式,所以不能显示绿色和红色的矩形。

更新2: @Günter的方式完全解决这个问题! 只是一个提醒,对Günter的方式:它至less需要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()); } } 

ViewEncapsulation.Emulated(默认)

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

D3没有Angulars的知识dynamic生成的HTML和Angular不能应用的类,使样式适用于生成的HTML。

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

ViewEncapsulation.None

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

“影子刺穿”

或者,您可以使用最近推出的阴影刺穿CSS组合器>>>/deep/::shadow::shadow刚刚被replace为 因此非常有限)。 另见https://stackoverflow.com/a/36225709/217408和Plunker

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

上海社会科学院

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

阴影parsingCSS组合器是由Angular重写的,并不需要浏览器支持。 Chrome支持他们一段时间,但是他们已经被弃用了,但是正如所说的那样,这并不重要,因为Angular重写了他们的封装模拟。

ViewEncapsulation.Native

Angular不支持从外部对这些组件进行样式化。 只有浏览器提供像CSSvariables这样的支持,才可以使用这些variables。

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

视图封装

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

 h2 { color: red; } 

它只会影响组件中的h2元素 ,而不会影响整个应用程序中的每个h2元素。 您可以在View封装的Angular文档中阅读更多关于这种机制的内容 。

为什么会影响你?

Angular会转换你的样式,但是由于C3graphics还没有绘制,所以它也不能转换HTML / SVG。 因此,组件样式将不匹配C3图中的元素。

我该怎么办?

外部样式表

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

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

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

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

ViewEncapsulation.None

您的第一个select是:使用图表(仅图表)创build一个组件,并closures其中的视图封装。 遵守单一责任原则也是一个好主意。 您的图表在devise上应该封装在一个单独的组件中。 视图封装的转向与将@Component装饰器添加其他属性一样简单:

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

/deep/ CSSselect器

如果出于某种原因,你不想这样做,还有另一种可能性。 你可以尝试在你的CSS中使用/deep/ selector,这样可以将样式强制到所有的子组件视图中。 有效地,这打破封装,应该影响你的C3图表。 所以,例如,你可以在你的组件的CSS文件中做到这一点:

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

无论哪种方式,我build议阅读前面提到的有关Angular 2中的视图封装的文档,以了解为什么发生这种情况以及它是如何工作的。 这个function应该可以帮助你编写代码,不会造成麻烦:)本文可能会帮助你理解它是如何工作的: 在blog.thoughtram.io上查看封装

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

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

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提到的。

testing

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

testing

Plunker


或者这个使用类.chart1.chart2 ,例如,如果你想。

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

testing

Plunker

我发现* /deep/ .my-element-class可以工作,但是出于某种原因,只有当svg父元素出现在html模板中时(而不是当svg父元素由d3dynamic创build时)。

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

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) ...