如何以及在何处使用 ::ng-deep?

How and where to use ::ng-deep?

我是 Angular 4 的新手,所以谁能解释一下 Angular 4 中如何以及在何处使用 ::ng-deep

其实我想从父组件中覆盖子组件的一些CSS属性。另外IE11支持吗?

感谢您的帮助。

通常 /deep/ “shadow-piercing” 组合子可用于将样式强制降低为 child components。这个选择器有一个别名 >>>,现在有另一个名为 ::ng-deep 的别名。

由于/deep/ combinator已弃用,建议使用::ng-deep

例如:

<div class="overview tab-pane" id="overview" role="tabpanel" [innerHTML]="project?.getContent( 'DETAILS')"></div>

css

.overview {
    ::ng-deep {
        p {
            &:last-child {
                margin-bottom: 0;
            }
        }
    }
}

它将应用于子组件

用法

::ng-deep>>>/deep/ 禁用特定 CSS 规则的视图封装,换句话说,它允许您访问 DOM 元素,它们不在您的组件 HTML 中。例如,如果您正在使用 Angular Material(或任何其他类似的第三方库),一些生成的元素在您的组件区域之外(例如 dialog)并且您无法访问这些元素元素直接或使用常规 CSS 方式。如果你想改变那些元素的样式,你可以使用这三个东西之一,例如:

::ng-deep .mat-dialog {
  /* styles here */
}

目前 Angular 团队建议仅使用 EMULATED 视图封装进行 "deep" 操作。

弃用

"deep"操作实际上是deprecated too, BUT it stills working for now, because Angular does pre-processing support (don't rush to refuse ::ng-deep today, take a look at deprecation practices先)。

无论如何,在采用这种方式之前,我建议您先看看 禁用视图封装 方法(这也不太理想,它允许您的样式泄漏到其他组件中),但在某些情况下,这是更好的方法。如果您决定禁用视图封装,强烈建议使用特定的 类 来避免 CSS 规则交集,最后,避免样式表混乱。在组件的 .ts 文件中禁用它真的很容易:

@Component({
  selector: '',
  template: '',
  styles: [''],
  encapsulation: ViewEncapsulation.None  // Use to disable CSS Encapsulation for this component
})

您可以在 this 文章中找到有关视图封装的更多信息。

确保不要错过 angular 指南中 ::ng-deep 正上方的 :host-context 的解释:https://angular.io/guide/component-styles。直到现在我都错过了它,希望我能早点看到它。

::ng-deep 在您没有编写组件且无权访问其源代码时通常是必需的,但是 :host-context 在您编写时可能是一个非常有用的选项。

例如,我设计的组件中有一个黑色 <h1> header,我希望能够在它显示在深色主题背景上时将其更改为白色。

如果我无法访问源代码,我可能必须在 css 中为 parent:

.theme-dark widget-box ::ng-deep h1 { color: white; }

但是 :host-context 您可以在 内部 组件中执行此操作。

 h1 
 {
     color: black;       // default color

     :host-context(.theme-dark) &
     {
         color: white;   // color for dark-theme
     }

     // OR set an attribute 'outside' with [attr.theme]="'dark'"

     :host-context([theme='dark']) &
     {
         color: white;   // color for dark-theme
     }
 }

这将在组件链中的任何位置查找 .theme-dark,如果找到,则将 css 应用到 h1。这是一个很好的替代方法,可以避免过度依赖 ::ng-deep,而 ::ng-deep 虽然经常需要,但有点 anti-pattern.

在这种情况下,&h1 替换(这就是 sass/scss 的工作方式),因此您可以定义 'normal' 和 themed/alternative css 紧挨着,非常方便。

注意获取正确的:个数。 ::ng-deep有两个,:host-context只有一个。

只是更新:

您应该使用 ::ng-deep 而不是 /deep/,后者似乎已被弃用。

根据文档:

The shadow-piercing descendant combinator is deprecated and support is being removed from major browsers and tools. As such we plan to drop support in Angular (for all 3 of /deep/, >>> and ::ng-deep). Until then ::ng-deep should be preferred for a broader compatibility with the tools.

你可以找到它here

我想强调将 ::ng-deep 限制为仅组件的子组件的重要性,方法是要求父组件是封装的 css class.

为了让它工作,重要的是在父级之后使用 ::ng-deep,而不是之前,否则它会在加载组件时应用到所有具有相同名称的 classes。

::ng-deep 之前使用 :host 关键字将自动处理此问题:

:host ::ng-deep .mat-checkbox-layout

或者,您可以通过在 ::ng-deep 关键字之前添加范围为 CSS class 的组件来实现相同的行为:

.my-component ::ng-deep .mat-checkbox-layout {
    background-color: aqua;
}

组件模板:

<h1 class="my-component">
    <mat-checkbox ....></mat-checkbox>
</h1>

Resulting (Angular generated) css 将包含唯一生成的名称并仅应用于它自己的组件实例:

.my-component[_ngcontent-c1] .mat-checkbox-layout {
    background-color: aqua;
}

谨慎使用 ::ng-deep。我在整个应用程序中都使用它来将 material 设计工具栏颜色设置为整个应用程序中的不同颜色,结果发现当应用程序测试工具栏颜色时,它们会相互叠加。来找出它是因为这些样式成为全局的,请参阅this article这是一个不会渗入其他组件的工作代码解决方案。

<mat-toolbar #subbar>
...
</mat-toolbar>

export class BypartSubBarComponent implements AfterViewInit {
  @ViewChild('subbar', { static: false }) subbar: MatToolbar;
  constructor(
    private renderer: Renderer2) { }
  ngAfterViewInit() {
    this.renderer.setStyle(
      this.subbar._elementRef.nativeElement, 'backgroundColor', 'red');
  }

}