D3.js 组件中的样式未以角度 2 显示

Posted

技术标签:

【中文标题】D3.js 组件中的样式未以角度 2 显示【英文标题】:Styles in component for D3.js do not show in angular 2 【发布时间】:2016-07-12 21:23:12 【问题描述】:

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

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

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

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

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

更新 2: @Günter 的方式完美解决了这个问题!!提醒一下,对于 Günter 的方式:它至少需要 Angular beta 10。(我的其他 plunkrs 使用 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());
  

【问题讨论】:

似乎正在工作。你检查了吗? @micronyks 仅在 style.css 文件中的 styes 时有效。 似乎在工作clipular.com/c/… @Cyril 是的,当麦粒肿仅在 style.css 文件中时有效 【参考方案1】:

更新

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

ViewEncapsulation.Emulated(默认)

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

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

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

ViewEncapsulation.None

对于encapsulation: ViewEncapsulation.None,Angular 不会进行这种重写,因此结果类似于将 HTML 添加到 index.html

“穿影”

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

:host /deep/ div 
  color: red;

SASS

/deep/ 可以在 SASS 中正常工作,但别名 &gt;&gt;&gt; 不能。

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

ViewEncapsulation.Native

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

【讨论】:

谢谢你,君特!!它现在完美无缺!!那些穿透 CSS 组合器 &gt;&gt;&gt;/deep/::shadow 的东西太棒了!我觉得我需要学习的东西太多了。 只是提醒其他人:为此,它至少需要 Angular beta 10。(我的其他 plunkrs 使用 Angular beta 8)使用 Angular beta 12 的绿色和一个红色矩形的工作演示是here. 嗨,Günter,这些 CSS 组合器是否已弃用?如果是,那么还有其他方法吗? chromestatus.com/feature/6750456638341120 “这不起作用”不知道你认为我应该怎么做。你可能做错了什么,但我们怎么知道? 这有助于在折线图上显示数据点的“点”:将以下内容添加到我的 reportgraph.component.css 文件中:&gt;&gt;&gt; #reportClubSignupRate .nv-point fill-opacity: 1 !important; 【参考方案2】:

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

【讨论】:

你能解释一下吗?这将更有帮助。谢谢 egghead.io/lessons/… 只需观看此视频一次,您就会了解 angular2 中可用的三种不同方式。 看完这个视频,基本上是让样式全局化了,然后就像在style.css中使用一样,请看这个plunkr,然后我不能显示一个红色和一个绿色的矩形......问题又来了【参考方案3】:

查看封装

这是因为 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,则必须有一些方法可以添加外部样式表。可能最简单的方法是在您的index.html 文件中的&lt;head&gt; 中添加另一个&lt;link …&gt;

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

【讨论】:

【参考方案4】:

你可以使用

::ng-deep
.bar 
    fill: red;

Here you can read perfect article explaining the approach.

And... information from the Angular documentation

【讨论】:

请编辑此答案以响应特定问题的方式描述此代码的作用。【参考方案5】:

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

我认为这是一些覆盖,我不知道这在多大程度上是正确的,但我认为这可以解决您的问题。

例如添加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

【讨论】:

谢谢,@angel-angel,它们是非常好的替代方法,但我有几十个这样的小组件,每个组件也被重复使用数十甚至数百次。如果我不能将它们的样式限制在它们自己的组件中,那将很难维护。【参考方案6】:

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

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

我的组件.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)
 ...

【讨论】:

以上是关于D3.js 组件中的样式未以角度 2 显示的主要内容,如果未能解决你的问题,请参考以下文章

外部脚本未以角度 5 动态加载

角度 1.5 中的组件样式?

d3.js:饼图布局 - 调整角度以创建快门效果

如何在全局样式表中设置角度4组件选择器的样式?

D3.js 弧生成器 (V3版本)

为啥角度组件不尊重样式 css?