Angular 7 CSS在使用可重用组件时不起作用

Posted

技术标签:

【中文标题】Angular 7 CSS在使用可重用组件时不起作用【英文标题】:Angular 7 CSS not working while using reusable component 【发布时间】:2019-06-27 12:11:00 【问题描述】:

我是 Angular 的新手,来自 React.js 背景。

我做了一个简单的网格组件,如下所示:

grid.component.js

import  Component, OnInit, Input  from '@angular/core';

@Component(
  selector: 'app-grid',
  template: `
    <div [ngStyle]="styles()" [ngClass]="passClass">
      <ng-content></ng-content>
    </div>
  `,
  styles: [`
    div 
      display: flex;
    
  `]
)
export class GridComponent implements OnInit 
  @Input() direction: string;
  @Input() justify: string;
  @Input() align: string;
  @Input() width: string;
  @Input() passClass: string;

  constructor()  

  ngOnInit() 
  

  styles() 
    return 
      'flex-direction': this.direction || 'row',
      'justify-content': this.justify || 'flex-start',
      'align-items': this.align || 'flex-start',
      ...(this.width &&  width: this.width )
    ;
  

我想在其他组件中使用它,如下所示: aboutus.component.html

<app-grid passClass="about-us page-container">
  <app-grid direction="column" passClass="left">
    <div class="title blue bold">
      An open community For Everyone
    </div>
    <div class="large-desc grey">
      This conference is brought to you by
      the Go Language Community in
      India together with the Emerging
      Technology Trust (ETT). ETT is a non-
      profit organization, established to
      organize and conduct technology
      conferences in India. It’s current
      portfolio includes
    </div>
  </app-grid>
</app-grid>

aboutus.component.sass

.about-us
  position: relative
  .left
    width: 50%
    &:after
      bottom: 0
      right: 0
      z-index: 0
      margin-right: -5vw
      position: absolute
      content: url(../../assets/images/footer.svg)

但是,第二个组件附带的 CSS 将不起作用。

我对 CSS 隔离有点了解,但不明白它是否会影响这里。

P.S.:请随时对超出此问题范围的内容提供反馈。

【问题讨论】:

【参考方案1】:

不能在模板中将 CSS 类作为变量传递。因此,如果您对 aboutus.component.html 的期望是能够将 left CSS 类作为变量传递到您的模板中,那将无法正常工作。

我可以指出一些希望对您有所帮助的事情:

    如果要从组件外部修改组件内部的 CSS 类,一种选择是使用 ng-deep。

    在您的特定情况下,我认为 ng-deep 没有必要。我建议在app-grid 组件中删除div 元素,而是使用@HostBinding 装饰器将样式应用于宿主元素。使用这种方法,您可以完全删除 passCss,因为现在无论您在何处使用 app-grid 组件,您都可以使用 app-grid 选择器在 CSS 中设置该组件的样式。

    grid.component.ts:

    import  Component, OnInit, Input, HostBinding, SafeStyle  from '@angular/core';
    
    @Component(
      selector: 'app-grid',
      template: `<ng-content></ng-content>`,
      styles: [`
        :host 
          display: flex;
        
      `]
    )
    export class GridComponent implements OnInit 
      @Input() direction: string;
      @Input() justify: string;
      @Input() align: string;
      @Input() width: string;
    
      constructor(private sanitizer:DomSanitizer)  
    
      ngOnInit() 
      
    
      @HostBinding('style')
      styles(): SafeStyle 
        const styles = `
          flex-direction: $this.direction || 'row';
          justify-content: $this.justify || 'flex-start';
          align-items: $this.align || 'flex-start';
       `;
        return this.sanitizer.bypassSecurityTrustStyle(styles);
      
    
    

    aboutus.component.sass:

      app-grid 
        // You can style the host element of a component
        // just like any native HTML element and without
        // needing to use `ng-deep`
      
    

    您可能还想查看CSS Custom Properties。自定义 CSS 属性不受视图封装的屏蔽。如果您愿意,这使您能够为组件创建 CSS API,并且这些属性可以在组件内的任何位置使用。

    aboutus.component.sass

    app-grid 
      --image: url(../../assets/images/footer.svg)
    
    

    grid.component.sass

    div 
      content: var(--image);
    
    

【讨论】:

您的解决方案似乎是完美的。但是,您提到的代码存在一些问题。 @HostBinding('style') styles() 不起作用,我尝试绑定到 @HostBinding('attr.style'),然后据说它不安全。我必须像@HostBinding('style.flex-direction') 这样的单一样式绑定。您能否更新一下,我会将您的答案标记为正确。感谢您的回答。 哦对了,你必须使用DomSanitizer,如this answer所示。我会修改我的答案。 太棒了!再次感谢您的帮助。【参考方案2】:

如果您想在其他组件中设置某些元素的样式,请使用 :host/deep/ 修饰符(已弃用 - Alternative to /deep/)。有关此功能的更多信息,您可以阅读documentation

在您的情况下,这应该可以:

:host /deep/ 
    .left 
        width: 50%
        &:after 
          bottom: 0
          right: 0
          z-index: 0
          margin-right: -5vw
          position: absolute
          content: url(../../assets/images/footer.svg)
       
    

您还可以禁用此组件的封装:

@Component(
  selector: 'app-grid',
  template: `
    <div [ngStyle]="styles()" [ngClass]="passClass">
      <ng-content></ng-content>
    </div>
  `,
  styles: [`
    div 
      display: flex;
    
  `],
  encapsulation: ViewEncapsulation.None
)

【讨论】:

谢谢,在 aboutus 组件 css 中? 不是 /deep/ 在 Angular 7 中被弃用了吗? 你是对的。不幸的是,我不知道任何替代方案 ***.com/questions/51708972/alternative-to-deep - 更多关于 Angular 弃用的信息 我对使用ViewEncapsulation.None 持怀疑态度我不确定它是否会影响其他事情。就像我在另一个组件中有div 选择器一样,我想它会受到影响吧?

以上是关于Angular 7 CSS在使用可重用组件时不起作用的主要内容,如果未能解决你的问题,请参考以下文章

Angular 可重用模块和组件

在 Angular 6 中使用具有输入属性的可重用组件

如何使用 Ionic 3 和 Angular 4 创建可重用组件

使用 Angular 9 和 Material 设计的可重用输入组件

Angular Material mat-table 在组件中定义可重用列

如何编写可重用的组件/模块?