首页 文章

如何从父组件的CSS文件设置子组件的样式?

提问于
浏览
171

我有一个父组件:

<parent></parent>

我想用子组件填充这个组:

<parent>
  <child></child>
  <child></child>
  <child></child>
</parent>

父模板:

<div class="parent">
  <!-- Children goes here -->
  <ng-content></ng-content>
</div>

儿童模板:

<div class="child">Test</div>

由于 parentchild 是两个单独的组件,因此它们的样式将锁定在自己的范围内 .

在我的父组件中,我尝试过:

.parent .child {
  // Styles for child
}

.child 样式未应用于 child 组件 .

我尝试使用 styleUrlsparent 的样式表包含到 child 组件中以解决范围问题:

// child.component.ts
styleUrls: [
  './parent.component.css',
  './child.component.css',
]

但这没有帮助,也尝试了另一种方式将 child 样式表提取到 parent 但这也无济于事 .

那么如何设置包含在父组件中的子组件的样式?

13 回答

  • 1

    更新 - 最新方式

    如果可以避免的话,不要这样做 . 正如Devon Sans在评论中指出的那样:这个功能很可能会被弃用 .

    更新 - 更新的方式

    Angular 4.3.0 开始,所有穿孔的css组合都被弃用了 . Angular团队推出了一个新的组合器 ::ng-deep (still it is at experimental level and not the full and final way) ,如下所示,

    DEMO : https://plnkr.co/edit/RBJIszu14o4svHLQt563?p=preview

    styles: [
        `
         :host { color: red; }
    
         :host ::ng-deep parent {
           color:blue;
         }
         :host ::ng-deep child{
           color:orange;
         }
         :host ::ng-deep child.class1 {
           color:yellow;
         }
         :host ::ng-deep child.class2{
           color:pink;
         }
        `
    ],
    
    
    
    template: `
          Angular2                                //red
          <parent>                                //blue
              <child></child>                     //orange
              <child class="class1"></child>      //yellow
              <child class="class2"></child>      //pink
          </parent>      
        `
    

    老路

    你可以使用 encapsulation mode 和/或 piercing CSS combinators >>>, /deep/ and ::shadow

    工作示例:http://plnkr.co/edit/1RBDGQ?p=preview

    styles: [
        `
         :host { color: red; }
         :host >>> parent {
           color:blue;
         }
         :host >>> child{
           color:orange;
         }
         :host >>> child.class1 {
           color:yellow;
         }
         :host >>> child.class2{
           color:pink;
         }
        `
        ],
    
    template: `
      Angular2                                //red
      <parent>                                //blue
          <child></child>                     //orange
          <child class="class1"></child>      //yellow
          <child class="class2"></child>      //pink
      </parent>      
    `
    
  • 0

    UPDATE 3:

    ::ng-deep 也被弃用,这意味着你不应该再这样做了 . 目前还不清楚这会如何影响您需要从父组件覆盖子组件中的样式的内容 . 对我而言,如果完全删除它似乎很奇怪,因为这会影响作为库需要覆盖库组件中的样式的库?

    如果您对此有任何见解,请发表评论 .

    UPDATE 2:

    由于 /deep/ 和所有其他阴影穿孔选择器现已弃用 . Angular删除 ::ng-deep ,应该使用它来代替更广泛的兼容性 .

    UPDATE:

    如果使用Angular-CLI,则需要使用 /deep/ 而不是 >>> ,否则它将无效 .

    ORIGINAL:

    在转到Angular2的Github页面并随机搜索"style"后,我发现了这个问题:Angular 2 - innerHTML styling

    据说使用了 2.0.0-beta.10>>>::shadow 选择器中添加的内容 .

    (>>>)(和等效/深/)和:: shadow在2.0.0-beta.10中添加 . 它们类似于shadow DOM CSS组合器(不推荐使用),仅适用于封装:ViewEncapsulation.Emulated,这是Angular2中的默认值 . 它们可能也适用于ViewEncapsulation.None但只是被忽略,因为它们不是必需的 . 在支持跨组件样式的更高级功能之前,这些组合器只是一种中间解决方案 .

    所以简单地做:

    :host >>> .child {}
    

    parent 的样式表文件中解决了这个问题 . 请注意,如上面引用中所述,此解决方案仅在支持更高级的跨组件样式之前才是中间的 .

  • 169

    有同样的问题,所以如果你使用angular2-cli和scss / sass使用'/ deep /'而不是'>>>',那么最后的选择器还不支持(但是对css很有用) .

  • 10

    遗憾的是,似乎已弃用/ deep / selector(至少在Chrome中)https://www.chromestatus.com/features/6750456638341120

    简而言之,似乎(目前)没有长期解决方案,除了以某种方式让您的子组件动态地设置事物 .

    您可以将样式对象传递给您的孩子并通过以下方式应用它:
    <div [attr.style]="styleobject">

    或者,如果您有特定的风格,您可以使用以下内容:
    <div [style.background-color]="colorvar">

    更多与此相关的讨论:https://github.com/angular/angular/issues/6511

  • 0

    如果您希望更多地针对实际的子组件而不是您应该执行的操作 . 这样,如果其他子组件共享相同的类名,则不会受到影响 .

    Plunker:https://plnkr.co/edit/ooBRp3ROk6fbWPuToytO?p=preview

    例如:

    import {Component, NgModule } from '@angular/core'
    import {BrowserModule} from '@angular/platform-browser'
    
    @Component({
      selector: 'my-app',
      template: `
        <div>
          <h2>I'm the host parent</h2>
          <child-component class="target1"></child-component>
    <child-component class="target2"></child-component>
    <child-component class="target3"></child-component>
    <child-component class="target4"></child-component>
    <child-component></child-component>
    </div> `, styles: [` /deep/ child-component.target1 .child-box { color: red !important; border: 10px solid red !important; } /deep/ child-component.target2 .child-box { color: purple !important; border: 10px solid purple !important; } /deep/ child-component.target3 .child-box { color: orange !important; border: 10px solid orange !important; } /* this won't work because the target component is spelled incorrectly */ /deep/ xxxxchild-component.target4 .child-box { color: orange !important; border: 10px solid orange !important; } /* this will affect any component that has a class name called .child-box */ /deep/ .child-box { color: blue !important; border: 10px solid blue !important; } `] }) export class App { } @Component({ selector: 'child-component', template: ` <div class="child-box"> Child: This is some text in a box </div> `, styles: [` .child-box { color: green; border: 1px solid green; } `] }) export class ChildComponent { } @NgModule({ imports: [ BrowserModule ], declarations: [ App, ChildComponent ], bootstrap: [ App ] }) export class AppModule {}

    希望这可以帮助!

    codematrix

  • 14

    如果你不想使用:: ng-deep,你可以这样做,这似乎是正确的方法:

    import { ViewEncapsulation } from '@angular/core';
    
    @Component({
        ....
        encapsulation: ViewEncapsulation.None
    })
    

    然后,您将能够在不需要:: ng-deep的情况下修改组件的css

    .mat-sort-header-container {
      display:flex;
      justify-content:center;
    }
    

    警告:小心你的组件有很多孩子,你为这个组件编写的CSS可能会影响所有孩子!

  • 3

    在Angular中有几个选项可以实现:

    1)您可以使用深度css选择器

    :host >>> .childrens {
         color: red;
     }
    

    2)你也可以将它设置为Emulated的视图封装更改为默认设置,但可以很容易地更改为使用Shadow DOM本机浏览器实现的Native,在你的情况下你只需要禁用它

    例如:`

    import { Component, ViewEncapsulation } from '@angular/core';
    
    @Component({
      selector: 'parent',
      styles: [`
        .first {
          color:blue;
        }
        .second {
          color:red;
        }
     `],
     template: `
        <div>
          <child class="first">First</child>
          <child class="second">Second</child>
        </div>`,
      encapsulation: ViewEncapsulation.None,
     })
     export class ParentComponent  {
       constructor() {
    
       }
     }
    
  • 47

    如果您有权访问子组件代码,我会发现很多 cleaner to pass an @INPUT variable

    这个想法是父母告诉孩子它的外貌应该是什么,孩子决定如何显示状态 . 这是一个很好的建筑

    SCSS Way:

    .active {
      ::ng-deep md-list-item {
        background-color: #eee;
      }
    }
    

    Better way: - 使用 selected 变量:

    <md-list>
        <a
                *ngFor="let convo of conversations"
                routerLink="/conversations/{{convo.id}}/messages"
                #rla="routerLinkActive"
                routerLinkActive="active">
            <app-conversation
                    [selected]="rla.isActive"
                    [convo]="convo"></app-conversation>
        </a>
    </md-list>
    
  • 15

    您不应该为父组件中的子组件元素编写CSS规则,因为Angular组件是一个自包含的实体,应该明确声明可用于外部世界的内容 . 如果子布局将来发生更改,那么子组件元素的样式将分散在其他组件中' SCSS files could easily break, thus making your styling very fragile. That' s在CSS的情况下 ViewEncapsulation 的用途 . 否则,如果您可以从面向对象编程中的任何其他类为某些类的私有字段赋值,那么它将是相同的 .

    因此,您应该做的是定义一组可以应用于子宿主元素的类,并实现子代对它们的响应方式 .

    从技术上讲,它可以如下完成:

    // child.component.html:
    <span class="label-1"></span>
    
    // child.component.scss:
    :host.child-color-black {
        .label-1 {
            color: black;
        }
    }
    
    :host.child-color-blue {
        .label-1 {
            color: blue ;
        }
    }
    
    // parent.component.html:
    <child class="child-color-black"></child>
    <child class="child-color-blue"></child>
    

    换句话说,您使用Angular CSS类集提供的 :host 伪选择器来定义子组件本身中可能的子样式 . 然后,您可以通过将预定义的类应用于 <child> host元素来从外部触发这些样式 .

  • 0

    答案很简单,你根本就不应该这样做 . 它打破了组件封装并破坏了从自包含组件中获得的好处 . 考虑将prop标志传递给子组件,然后可以根据需要决定自己如何以不同方式呈现或应用不同的CSS .

    <parent>
      <child [foo]="bar"></child>
    </parent>
    

    Angular正在弃用影响父母子女风格的所有方式 .

    https://angular.io/guide/component-styles#deprecated-deep--and-ng-deep

  • 9

    我提出了一个例子,以便更清楚,因为angular.io/guide/component-styles陈述:

    不推荐使用阴影穿透后代组合器,并且正在从主要浏览器和工具中删除支持 . 因此,我们计划放弃Angular中的支持(对于/ deep /,>>>和:: ng-deep的所有3个) . 在此之前:: ng-deep应该是首选,以便与工具更广泛地兼容 .

    app.component.scss 上,根据需要导入 *.scss . _colors.scss 有一些常见的颜色值:

    $button_ripple_red: #A41E34;
    $button_ripple_white_text: #FFF;
    

    Apply a rule to all components

    所有具有 btn-red 类的按钮都将被设置样式 .

    @import `./theme/sass/_colors`;
    
    // red background and white text
    :host /deep/ button.red-btn {
        color: $button_ripple_white_text;
        background: $button_ripple_red;
    }
    

    Apply a rule to a single component

    将对 app-login 组件上具有 btn-red 类的所有按钮进行样式设置 .

    @import `./theme/sass/_colors`;
    
    /deep/ app-login button.red-btn {
        color: $button_ripple_white_text;
        background: $button_ripple_red;
    }
    
  • 6

    实际上还有一个选择 . 这是相当安全的 . 您可以使用ViewEncapsulation.None但是将所有组件样式放入其标记(也称为选择器) . 但无论如何总是喜欢一些全局风格加封装样式 .

    这里修改了Denis Rybalka的例子:

    import { Component, ViewEncapsulation } from '@angular/core';
    
    @Component({
      selector: 'parent',
      styles: [`
        parent {
          .first {
            color:blue;
          }
          .second {
            color:red;
          }
        }
     `],
     template: `
        <div>
          <child class="first">First</child>
          <child class="second">Second</child>
        </div>`,
      encapsulation: ViewEncapsulation.None,
    })
    export class ParentComponent  {
      constructor() { }
    }
    
  • 4

    我也有这个问题,并不想使用已弃用的解决方案,所以我最终得到:

    在parrent

    <dynamic-table
      ContainerCustomStyle='width: 400px;'
      >
     </dynamic-Table>
    

    子组件

    @Input() ContainerCustomStyle: string;
    

    在html div的孩子

    <div class="container mat-elevation-z8"
     [style]='GetStyle(ContainerCustomStyle)' >
    

    并在代码中

    constructor(private sanitizer: DomSanitizer) {  }
    
      GetStyle(c) {
        if (isNullOrUndefined(c)) { return null; }
        return  this.sanitizer.bypassSecurityTrustStyle(c);
      }
    

    像预期的那样工作,不应该弃用;)

相关问题