我正在使用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());
}
}
答案 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/217408和Plunker
: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-cmp
,child1-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提及。
测试
或者这个:
@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: []
})
测试
或使用课程.chart1
,.chart2
,例如,如果您愿意。
@Component({
selector: 'my-app',
directives: [Child1Cmp, Child2Cmp],
encapsulation: ViewEncapsulation.None,
styles: [`
.chart1 .bar {
fill: red;
}
.chart2 .bar {
fill: yellow;
}
`],
..//
测试
答案 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)
...