【问题标题】:Angular2 Styles in a Directive指令中的 Angular2 样式
【发布时间】:2016-06-25 05:38:36
【问题描述】:

在给定的属性指令示例(即添加外观/行为的指令)中,我们对宿主元素的样式进行了相当简单的设置..例如

import {Directive, ElementRef } from 'angular2/core';
@Directive({
    selector: '[myHighlight]'
})
export class HighlightDirective {
    constructor(element) {
       element.nativeElement.style.backgroundColor = 'yellow';
    }

static get parameters(){
    return [[ElementRef]];
}

我可以使用样式而不是设置样式吗?例如

@Directive({
    selector: '[myHighlight]',
    styles: [':host { background-color: yellow; }']
})

这似乎不适合我?

我正在做一些稍微复杂一些的事情,这导致了相当多的单一代码、设置大量样式、使用 AnimationBuilder 等等等。我觉得将它分成类和动画会更好一个 CSS。

ViewEncapsulation = 模拟/默认是否重要?

【问题讨论】:

  • 虽然已经一年了,但为了后代,我在下面添加了答案。它既涉及使用组件作为指令,又涉及更改默认的 ViewEncapsulation。请看下面我的回答。 - 干杯

标签: angular angular2-directives


【解决方案1】:

您可以使用主机绑定来绑定样式属性:

@Directive({
    selector: '[myHighlight]',
    host: {
      '[style.background-color]': '"yellow"',
    }
})

@Directive({
    selector: '[myHighlight]',
})
class MyDirective {
  @HostBinding('style.background-color')
  backgroundColor:string = 'yellow';
}

【讨论】:

  • 谢谢,但这仍然给我留下了需要单独设置 n 个属性而不是使用内联/外部 CSS 的问题?在这个简单的例子中很好,但是如果我有 30 多个带有动画的规则,并且这些规则可以在不同的状态/组合下应用,例如悬停,点击等。
  • 在这种情况下感谢您的回答比向 ElementRef 添加依赖项要好得多!
  • 这是 Angular 提供的。只有组件支持添加样式表(内联或导入)。 (styles, styleUrls)。
  • 如果我有一个带有 @primaryColour 的 LESS 文件并且我需要设置该样式怎么办?
  • @David 我不明白你的问题,也许是因为我不知道 LESS。
【解决方案2】:

虽然其他答案在大多数情况下都有帮助,但您似乎需要一种更传统的 CSS 样式表方法,就像我有一个用例一样。

问题在于 Angular 默认模拟 Shadow DOM,它仅在宿主元素内限定样式。

两种选择:

1)

您可以使用:host /deep/ .some-style-to-cascade-down-like-normal {} 告诉Angular 将您的样式向下级联到其所有后代,或将/deep/ 替换为>>>。请参阅Angular's Docs

需要注意的三个重要事项:

  • ViewEncapsulation 需要为其默认(模拟)状态
  • Angular/Chrome 正在弃用这两种语法,同时他们正在研究更好的方法
  • 如果您使用 Angular CLI,则必须使用 /deep/ 而不是 >>>

2)

虽然您将松散范围内的组件封装(如果这对您的情况很重要),但这里有一个使用“myHighlight”作为指令的示例,尽管 TypeScripted 作为组件 所以我可以导入样式表:

用法:
<p myHighlight>Highlight me!</p>

TS(组件被视为指令):

import {
    Component,
    ViewEncapsulation
} from '@angular/core';

@Component({
    selector: 'p[myHighlight]', // Refer to it like an attribute directive
    templateUrl: './my-highlight.component.html',
    styleUrls: ['./my-highlight.component.scss'],
    encapsulation: ViewEncapsulation.None // Tell Angular to not scope your styles
})

Angular Material 2's Button 使用同样的方法来解决这个问题。

还有一篇很棒的文章,名为 All the Ways to Add CSS to Angular 2 Components,它让我意识到了这一点,并解释了 Angular 如何处理所有三个 ViewEncapsulation 属性。

【讨论】:

  • 支持“封装:ViewEncapsulation.None”:D
  • "Angular Material 2 的 Button 使用同样的方法来解决这个问题。" - 他们确实使用了您正在使用的技术,并且选择器类似于指令。但与本主题不同的是,他们并没有尝试将样式添加到指令中。对于那些决定将指令转换为组件只是为了这种风格的人,你使用什么模板?您能否添加您的 .\my-highlight.component.html 以便我们了解如何完成这项工作?这不会与由相同元素制成的其他组件冲突吗?例如
  • @jcairney <ng-content></ng-content>my-highlight.component.html的重要组成部分
  • 这是OP提出的问题的最佳答案
  • 关于 >>> ::ng-deep 和 /deep/ 的使用已经有了一些发展。看起来这些很快就会被贬值,并且从上面的链接中可以看出“在那之前 ::ng-deep 应该是首选,以便与工具更广泛地兼容。”
【解决方案3】:

我已阅读您在第一个答案下方的评论。我不知道您将如何应用您的 30 条规则。 But few ways are here- plunker.

selector:"[myHighlight]", 
    host: {        
    '(mouseenter)':'changeColor()',
    '[style.background]': '"pink"', 
    '(click)':'clickMe()',
    '(mouseout)':'changeColorOnOut()',
  }

【讨论】:

    【解决方案4】:

    这个答案为时已晚,但在我的同类需求中使用了一个棘手的解决方案,所以我觉得它可能会对某人有所帮助。

    我是按以下方式完成的,它对我有用

    <div class="someClass" customDirective>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</div>
    
    import { Directive, ElementRef } from '@angular/core';
    @Directive({
    selector: '[customDirective]'
    })
    export class CustomDirective {
      domElement: any;
    
      constructor(private elementRef: ElementRef) {
      this.domElement = this.elementRef.nativeElement;
      const newStyles = {
         'background-color': 'yellow',
         'color': 'red',
         'font-weight': 'bold',
         //...and so on
        };
       Object.keys(newStyles).forEach(element => {
         this.domElement.style.setProperty(`${element}`,newStyles[element]);
        }      
    
      } 
    //Other logic required for the directive...
    
    }
    

    Working Example

    【讨论】:

      【解决方案5】:

      与@m.spyratos 相同,但使用 Renderer2:

      import {
        Directive,
        ElementRef,
        OnInit,
        Renderer2
      } from '@angular/core';
      
      @Directive({
        selector: '[myButton]'
      })
      export class MyButtonDirective implements OnInit {
        constructor(
          private elementRef: ElementRef,
          private renderer: Renderer2
        ) { }
      
        public ngOnInit(): void {
          this.renderer.addClass(
            this.elementRef.nativeElement,
            'my-button'
          );
        }
      }
      

      【讨论】:

      • 为什么要做所有这些而不是仅仅编写针对指令属性的 CSS 样式?例如[myButton] { ....styles here }
      • 好问题。一个潜在的用例是您希望将现有的全局 CSS 类名称附加到指令元素。另一个用例:您想根据某些条件以编程方式添加 CSS 类名。
      • 我不明白定位类名和定位指令属性名之间的区别。此外,您何时/如何添加类名与您的 CSS 是否会启动没有任何关系。我不明白这两件事是如何相关的。
      • 当一个全局样式表定义了一个 CSS 类(比如,在你从 NPM 安装的另一个库中)并且已经添加到你的根 HTML 模板的页面中,也许你想将该类名附加到你的指令元素?也许您只想在某些条件下添加全局类名?我会说这些都是有效的用例。
      【解决方案6】:

      只需像通常使用属性选择器一样设置元素的样式。在与您的指令相同的文件夹中创建一个myHighlight.directive.scss(或其他)文件,并在其中写入您的样式:

      [myhighlight] {
        background-color: yellow;
      }
      

      如果您的应用没有自动包含您的样式文件,只需将其导入您的主样式文件即可。对我来说,在 Ionic 2 中它是自动拾取的。

      如果你想使用特定的类而不是属性选择器,那么使用渲染器来添加类。

      import {Directive, ElementRef, Renderer} from 'angular2/core';
      @Directive({
          selector: '[myHighlight]'
      })
      export class HighlightDirective {
          constructor(private el: ElementRef, private renderer: Renderer) {
              this.renderer.setElementClass(this.el.nativeElement, 'my-highlight', true);
          }
      }
      

      【讨论】:

      • 使用第一种方法对我不起作用。使用 Angular 2.4。如果我需要导入 global.scss,我会丢失样式封装。您只能将自定义类设置为指令或使用没有视图封装的@Component。
      • 为我工作。当我将元素选择器更改为属性选择器并将属性选择器添加到组件中的ion-card 元素时,将parentElement{ ion-card{ &lt;mystyles&gt; }} 更改为[parentElement]{ &lt;mystyles&gt; }
      • @aelkz:我参加聚会有点晚了,但它在 Angular 5 和 Ionic 3 中对我有用。您是否检查过 scss 中的选择器与 .ts 中的选择器不同文件?又名,在 .ts 文件中,它通常显示“selector:[mySelectorSomething]”,并且为了让 scss 产生一些效果,它必须引用全小写,也就是 [myselectorsomething]:{},如上例所述。这是相当微妙的,不是很合乎逻辑,所以很容易错过(至少对我来说是这样)。
      • 改进 Angular 5 可能会更好。
      猜你喜欢
      • 1970-01-01
      • 2017-09-02
      • 1970-01-01
      • 2018-08-14
      • 2016-12-22
      • 2017-07-31
      • 2017-05-26
      • 2020-11-09
      • 2016-07-16
      相关资源
      最近更新 更多