我的 Angular router-outlet 元素上的这个样式属性来自哪里?

Where is this style attribute on my Angular router-outlet element coming from?

所以我有一个 Angular 应用程序,它具有非常基本的路由,并且我正在使用 flexbox 来布局我的组件。我无法弄清楚的问题是这样的代码:

  <div fxLayout="column"
       fxFlex
       class="layout__right">
    <router-outlet></router-outlet>

  </div>

路由到的子组件在其 SCSS 中包含以下内容:

:host {
    @include make-flex-container(column);
    flex: 1;
}

make-flex-container 只是应用了一些与 flexbox 相关的样式,并且在应用程序的许多地方都可以正常工作。在我的例子中发生的事情是,当路由到这个特定的子组件时,我看到一个 style 标记应用于由 Angular 创建的 ng-component 元素。导致我出现问题的原因是样式包含 flexbox 项目,这些项目覆盖了我在 :host:

中的内容

您可以在屏幕截图中看到我的 :host 样式已被应用,但 ng-component 标签上的样式只是简单地覆盖了它们。对于我的生活,我不明白为什么这里添加了一个特定的 style 标签,所以其中的内容来自哪里。有谁知道为什么 Angular 会在为路由器插座生成的 HTML 上放置样式标签?当我导航到同一路由级别的其他组件时,此样式标签不存在。

我认为这是我的代码的一个问题,但我无法运行根据我所看到的内容去查看。

更新

以下是 Stackblitz 上问题的最小再现:

https://so-48451609-routing-flex-issue.stackblitz.io

在该示例中,您可以看到在路由器出口旁边创建的元素如何应用样式。唯一添加的依赖项是 @angular/flex-layout,因此它必须做一些事情才能导致此问题。

它们来自视图封装

我相信这些 类 是视图封装的一部分,可以防止 angular 元素从外部设置样式并防止视图组件之间的干扰。至少他们在官方文档中是这么说的 @angular.io。 正如建议的那样 '_ngcontent-c0' 是主机中第一个组件的命名。


ANGULAR MATERIAL 造成麻烦

我在 GitHub 发现了一堆与封装相关的问题,它们似乎通常与使用 Angular Material 有关,而 Angular Material 有时似乎以某种方式关闭了封装。如所述here。因此,我得出结论,您对 Angular Material 的实施可能有问题。为了深入分析这种不需要的交互的机制是什么,您可能希望从阅读 joh04667 对您的问题的回答开始,因为它提供了指向您使用的特定 material 文档的链接。


正确的样式

这些问题的常见解决方案是使用 /deep/ 选择器覆盖样式,如上述两个共享链接中所述。还有一些关于 Angular 应用程序样式的非官方文章,例如 this one.


想法

所以我的想法是用 /deep/ 覆盖组件中的样式,如下所示:

:host /deep/ .your_flex_class {
    @include make-flex-container(column);
    flex: 1;
}

考虑有效 CSS

因为我认为你使用的是 Scss,所以使用 /deep/ 选择器应该没问题,应该可以成功编译(我经常用它来设置内联 SVG 的样式)。然而,事实上,这个选择器似乎被弃用了,因为它是与 Shadow DOM 问题相关的一大堆东西。我相信正确的通用方法是使用 'shadow-piercing descendant combinator':

:host >>> .your_flex_class {
    @include make-flex-container(column);
    flex: 1;
}

它应该和 /deep/ 选择器一样。为了解释这个机制,让我引用 CSS Scoping Module Level 1

的官方文档

When a >>> combinator (or shadow-piercing descendant combinator) is encountered in a selector, replace every element in the selector match list with every element reachable from the original element by traversing any number of child lists or shadow trees.

基本上,它不关心包装器,而是咬住你的目标来设计它。因此,您还有更多选择可以尝试...

fxLayout 指令将样式应用于子元素。它在元素本身上执行此操作以不干扰其他样式。

@angular/flex-layout 库的静态 API 具有在 DOM 容器[=26 上工作的指令=] 元素fxLayout是前者的例子,fxFlex是后者的例子。

在此处查看文档,注意元素和容器的两个部分:https://github.com/angular/flex-layout/wiki/Declarative-API-Overview#api-for-dom-containers

好的,一旦我创建了一个工作示例,我最终找到了罪魁祸首和合适的解决方法。正在发生的事情发生在我的路由器子组件中,我正在使用 @angular/flex-layout 中的 fxFlex 来调整元素。我在组件 CSS 的 :host{} 部分应用了 flexbox 容器 CSS,但是 flex-layout 在呈现 HTML 并应用样式标签自动进行 flexbox 行布局。

这是一个关于 Github 的问题,其中包含我的评论以及在我的 :host{} CSS 中使用 !important 的合适解决方法:

https://github.com/angular/flex-layout/issues/496#issuecomment-360870510