【问题标题】:Angular 2+: How to programmatically add styles to child components that generate html?Angular 2+:如何以编程方式向生成 html 的子组件添加样式?
【发布时间】:2018-05-15 11:55:42
【问题描述】:

我有以下情况: 我创建了一个使用第 3 方组件的组件,该组件然后使用 JS 库(用于图表),然后生成我需要从我的组件设置样式的 HTML/SVG。

所以我们有类似的东西

(MyComponent) => (3rdPartyComponent) => (JSLibrary) => 动态生成的 HTML/SVG

生成的 SVG 看起来像这样:

<svg><g class="labels">...</g></svg>

因为单个页面上可以有多个图表,所以 MyComponent 可能会被多次实例化,并且每个生成的 SVG 的样式可能不同。

我现在想根据一些 @Input 到 MyComponent 以编程方式更改图表标签的字体大小,例如useSmallLables.

我该怎么做?

更多细节。 这是我想要的(不工作的)伪代码:

@Component({
  selector: 'app-my-component',
  template: '<third-party [ngClass]="getCssClasses()" ...></third-party>",
  style: ''
})
export class MyComponent ... {
  @Input() useSmallLabels = false;

  // we need a unique class name to be able to apply styles to a specific SVG, not all
  uniqueCssClass = generateSomeUniqueId();

  getCssClasses() {
    const cssOptions = {};

    // add the unique class
    cssOptions[this.uniqueCssClass] = true;

    // This it what I would like to do, but of course does not work with ngClass or anything else as far I know.
    // We would need ::ng-deep as the generated SVG does not know about angular emulated shadow-dom attributes and vice-versa
    const css = '::ng-deep .' + this.uniqueCssClass + ' .labels { font-size: 0.5rem; }';
    cssOptions[css] = this.useSmallLabels;

    return cssOptions;
}

我深入挖掘以找到解决此问题的方法,但我从未找到解决方案。使用老式的 JQuery 和其他东西,这可能根本不是问题。

【问题讨论】:

    标签: angular typescript sass


    【解决方案1】:

    您不能将实际样式添加到ngClass 指令,只能添加类名。您可以动态创建样式标签(似乎可以https://angular.io/guide/component-styles#template-inline-styles)并在那里添加逻辑:

    @Component({
        selector: 'app-my-component',
        template: `
            <style *ngIf="uniqueCssClass && useSmallLabels">
                .{{ uniqueCssClass }} ::ng-deep .labels {
                    font-size: 0.5rem;
                }
            </style>
            <third-party [ngClass]="getCssClasses()"></third-party>"
        `,
        style: ''
    })
    export class MyComponent ... {
        @Input() useSmallLabels = false;
    
        // we need a unique class name to be able to apply styles to a specific SVG, not all
        uniqueCssClass = generateSomeUniqueId();
    
        getCssClasses() {
            return this.uniqueCssClass;
        }
    }
    

    我不确定::ng-deep 是否适用于内联样式。如果它没有删除 ::ng-deep 并尝试将组件的 viewEncapsulation 设置为 none (https://angular.io/guide/component-styles#view-encapsulation)。但请注意,样式范围将成为全局范围,因此请将您的组件和样式包装到某个类中。我也不确定 viewEncapsulation 与内联样式的行为如何。

    【讨论】:

    • 内联样式是一个很好的提示,但我试过了,但它不起作用:一方面,因为{{ uniqueCssClass }} 不适用于内联样式,另一方面也是 ::ng -deep 似乎在生成的 CSS 中消失了(尽管我实际上并不知道 Angular 应该 在现实世界的 CSS 中从 ::ng-deep 中生成什么.../deep/?)。
    • Angular 有一个样式的位置,它不在模板内。这是一个黑客。
    • 就像我说的,角度文档在模板中提到了内联样式,所以我不会认为这是一种 hack。我理解为什么内联样式通常是个坏主意,但我想不出其他任何东西可以为动态生成的类添加样式。
    【解决方案2】:

    我终于找到了适合我的解决方案:

    @Component({
      selector: 'app-my-component',
      template: '<third-party [ngClass]="getCssClasses()" ...></third-party>",
      style: '.small-labels ::ng-deep .label { font-size: 0.5rem; }'
    })
    export class MyComponent ... {
      @Input() useSmallLabels = false;
    
      // we need a unique class name to be able to apply styles to a specific SVG, not all
      uniqueCssClass = generateSomeUniqueId();
    
      getCssClasses() {
        const cssOptions = {};
    
        // add the unique class
        cssOptions[this.uniqueCssClass] = true;
    
        // this activates or deactivates the ::ng-deep CSS style 
        cssOptions['small-labels] = this.useSmallLabels;
    
        return cssOptions;
    }
    

    当你有解决方案时,它突然看起来像一个非常简单的问题......

    我们仍然有问题,::ng-deep 现在已被弃用,所以当 Angular 放弃它时,我需要另一个解决方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-07-18
      • 1970-01-01
      • 2022-12-23
      • 2023-03-30
      • 2012-09-30
      • 2010-12-15
      • 2015-06-07
      相关资源
      最近更新 更多