我有一个父组件:

<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>

由于父组件和子组件是两个独立的组件,它们的样式被锁定在自己的范围内。

在我的父组件中,我尝试这样做:

.parent .child {
  // Styles for child
}

但是.child样式没有应用到子组件。

我尝试使用styleUrls将父组件的样式表包含到子组件中,以解决范围问题:

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

但这并没有帮助,我还尝试了另一种方法,将子样式表取到父样式表中,但这也没有帮助。

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


当前回答

截至目前(Angular 9), Angular使用Shadow DOM将组件显示为自定义HTML元素。为这些自定义元素设置样式的一种优雅方法可能是使用自定义CSS变量。下面是一个通用的例子:

class ChildElement extends HTMLElement { constructor() { super(); var shadow = this.attachShadow({mode: 'open'}); var wrapper = document.createElement('div'); wrapper.setAttribute('class', 'wrapper'); // Create some CSS to apply to the shadow dom var style = document.createElement('style'); style.textContent = ` /* Here we define the default value for the variable --background-clr */ :host { --background-clr: green; } .wrapper { width: 100px; height: 100px; background-color: var(--background-clr); border: 1px solid red; } `; shadow.appendChild(style); shadow.appendChild(wrapper); } } // Define the new element customElements.define('child-element', ChildElement); /* CSS CODE */ /* This element is referred as :host from the point of view of the custom element. Commenting out this CSS will result in the background to be green, as defined in the custom element */ child-element { --background-clr: yellow; } <div> <child-element></child-element> </div>

从上面的代码中可以看到,我们创建了一个自定义元素,就像Angular为每个组件所做的那样,然后我们从全局作用域覆盖自定义元素阴影根中的背景颜色变量。

在Angular应用中,这可能是这样的:

parent.component.scss

child-element {
  --background-clr: yellow;
}

child-element.component.scss

:host {
  --background-clr: green;
}

.wrapper {
  width: 100px;
  height: 100px;
  background-color: var(--background-clr);
  border: 1px solid red;
}

其他回答

截至目前(Angular 9), Angular使用Shadow DOM将组件显示为自定义HTML元素。为这些自定义元素设置样式的一种优雅方法可能是使用自定义CSS变量。下面是一个通用的例子:

class ChildElement extends HTMLElement { constructor() { super(); var shadow = this.attachShadow({mode: 'open'}); var wrapper = document.createElement('div'); wrapper.setAttribute('class', 'wrapper'); // Create some CSS to apply to the shadow dom var style = document.createElement('style'); style.textContent = ` /* Here we define the default value for the variable --background-clr */ :host { --background-clr: green; } .wrapper { width: 100px; height: 100px; background-color: var(--background-clr); border: 1px solid red; } `; shadow.appendChild(style); shadow.appendChild(wrapper); } } // Define the new element customElements.define('child-element', ChildElement); /* CSS CODE */ /* This element is referred as :host from the point of view of the custom element. Commenting out this CSS will result in the background to be green, as defined in the custom element */ child-element { --background-clr: yellow; } <div> <child-element></child-element> </div>

从上面的代码中可以看到,我们创建了一个自定义元素,就像Angular为每个组件所做的那样,然后我们从全局作用域覆盖自定义元素阴影根中的背景颜色变量。

在Angular应用中,这可能是这样的:

parent.component.scss

child-element {
  --background-clr: yellow;
}

child-element.component.scss

:host {
  --background-clr: green;
}

.wrapper {
  width: 100px;
  height: 100px;
  background-color: var(--background-clr);
  border: 1px solid red;
}

可悲的是/deep/选择器已弃用(至少在Chrome中) https://www.chromestatus.com/features/6750456638341120

简而言之,(目前)似乎没有长期的解决方案,除了以某种方式让你的子组件动态地设置样式。 你可以传递一个样式对象给你的孩子,并通过以下方式应用它: < div [attr.style] = " styleobject " > 或者如果你有一个特定的风格,你可以使用像这样的东西: < div [style.background-color] = " colorvar " >

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

我举一个例子来说明,因为角。io /指导/组件样式:

阴影穿透的后代组合子已弃用,并已从主要浏览器和工具中移除支持。因此,我们计划在Angular中放弃对/deep/、>>>和::ng-deep的支持。在此之前,::ng-deep应该优先考虑与这些工具的广泛兼容性。

在app.component.scss上,导入您的*。如有需要,可使用SCSS。_colors。SCSS有一些常见的颜色值:

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

对所有组件应用规则

所有具有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;
}

将规则应用到单个组件

app-login组件上所有具有btn-red类的按钮都将被样式化。

@import `./theme/sass/_colors`;

/deep/ app-login button.red-btn {
    color: $button_ripple_white_text;
    background: $button_ripple_red;
}

你不应该使用::ng-deep,它已被弃用。在Angular中,从父组件中改变子组件样式的正确方法是使用封装(阅读下面的警告以了解其含义):

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

@Component({
    ....
    encapsulation: ViewEncapsulation.None
})

然后,你就可以修改组件的css,而不需要使用::ng-deep

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

警告:这样做将使您为该组件编写的所有css规则都是全局的。

为了将你的css的范围限制在这个组件和他的子组件上,在你的组件的顶部标签上添加一个css类,并把你的css“放在”这个标签里:

模板:

<div class='my-component'>
  <child-component class="first">First</child>
</div>,

Scss文件:

.my-component {
  // All your css goes in there in order not to be global
}

我已经在Angular之外解决了这个问题。我已经定义了一个共享的scss,并将其导入到我的子程序中。

shared.scss

%cell {
  color: #333333;
  background: #eee;
  font-size: 13px;
  font-weight: 600;
}

child.scss

@import 'styles.scss';
.cell {
  @extend %cell;
}

我提出的方法是如何解决OP提出的问题。正如在多个场合提到的,::ng-deep,:ng-host将被贬低,在我看来,禁用封装只是太多的代码泄漏。