CSS 一个组件导致另一个组件出现不需要的格式

CSS of one component causing unwanted formatting in another

我还在学习Angular、CSS和HTML(这三个都是新的),所以请耐心等待我。

我收到了一些代码,并被赋予了修复一些格式的任务。

问题是:

首次加载页面时,页眉有一些填充。见左下图。

但是,当我导航到另一个页面时,该页面包含以下代码:

/* Removing padding and scroll bar from main page */
::ng-deep html > body > main#app-content {
    overflow-y: hidden;
    padding: 0;
}

然后导航到任何其他 component/page,填充消失了,所有内容都一直移动到屏幕左侧,这非常烦人。见右下图。注意:有人告诉我这是导致这种情况的代码,我实际上不知道它实际上在做什么(除了设置填充和 y-scroll)。

这张照片显示了两个 components/pages 在我使用上面的代码访问页面之前(显示在图片的左侧),然后在我使用上面的代码导航到该页面之后(显示在 t 上)嗯在图片的右侧)。请注意,绿线供参考,以显示填充是如何消失的。

所以我想在使用上面的代码访问页面后导航回原来的padding/formatting。

此外,有人可以向我解释为什么这样做吗?如果可能的话,代码的实际含义是什么?以下是一些具体问题:

  1. 我怎样才能阻止这种情况发生在另一个页面上?
  2. “::ng-deep html > body > main#app-content”是什么意思?
  3. 大号有什么作用?

TLDR: 这是一个 stackblitz,其中包含一个示例,说明如何使用服务而不是 ::ng-deep 来编辑全局样式。 https://stackblitz.com/edit/angular-ivy-p4pkdu?file=src/app/app.component.html


::ng-deep 是一项 angular 功能,可促进以下 css 全局应用(在您的应用程序中的任何地方)。它真的应该避免,因为通常有更好的方法来应用全局样式。此功能实际上已被弃用,我将在本答案末尾放置一个替代方案。

html > body > main#app-content 只是一个 CSS 选择器。在本例中,我们选择具有 id app-contentmain 元素,其父元素为 body,父元素为 html。这是 CSS 语法的一个很好的参考:https://www.w3schools.com/cssref/css_selectors.asp.

所以我们将这些 css 样式应用到类型为 main 且 ID 为 app-content 的 html 元素,该样式是全局应用的,因此它仍然会封装组件销毁后仍然存在。


::ng-deep 更好的替代方法是使用服务来编辑全局样式。首先,任何全局样式都应该存储或导入到全局样式文件中,通常在 angular 项目中称为 styles.css。如果你只需要一个组件中的样式,你可以将这个 css 放在相应的组件 css 文件中。我们将其声明为 class 以便我们可以将其动态添加到元素中。

styles.css

.noPaddingOrScrollbar {
  overflow-y: hidden;
  padding: 0;
}

然后使用 ng g service <serviceName> 通过 cli 生成服务。例如,要在名为 services 的文件夹中生成名为 globalStyleService 的服务,我们需要执行 ng g service services/global-style。我们将向我们的服务添加一个布尔值以指示我们是否要应用样式。

一个警告是我们需要使用 setTimeout 来设置布尔值,以避免可怕的 NG0100: Expression has changed after it was checked 错误。 setTimeout 将默认超时为零,但仍会延迟代码执行,直到 Angular 完成一轮更改检测。

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

@Injectable({
  providedIn: 'root',
})
export class GlobalStyleService {
  private _noPaddingOrScrollbar = false;

  set noPaddingOrScrollbar(value: boolean) {
    //Delay setting until after change detection finishes
    setTimeout(() => (this._noPaddingOrScrollbar = value));
  }

  get noPaddingOrScrollbar() {
    return this._noPaddingOrScrollbar;
  }

  constructor() {}
}

现在您需要找到这个 main#app-content 元素实际位于哪个组件中。它将位于父组件之一的 html 文件中。然后就可以在这个父组件的ts文件中注入服务,在组件的html文件中动态设置class

父组件ts文件

export class ParentComponent {
  constructor(public globalStyle: GlobalStyleService) {}
  ...
}

我们使用 angular 指令 [class.className]="boolean" 来动态设置 class。

父组件html文件

...
<main
  id="app-content"
  [class.noPaddingOrScrollbar]="globalStyle.noPaddingOrScrollbar"
></main>
...

现在您可以在应用程序的任何位置添加或删除此 class。所以在包含 hacky css 的组件中,我们注入服务,在 ngOnInit 期间添加样式并在 ngOnDestroy 期间删除它。当然,也要从 css 文件中删除 ::ng-deep 语句。

子组件ts文件

export class MyComponent implements OnInit, OnDestroy {
  constructor(private globalStyle: GlobalStyleService) {}

  ngOnInit(): void {
    this.globalStyle.noPaddingOrScrollbar = true;
  }

  ngOnDestroy(): void {
    this.globalStyle.noPaddingOrScrollbar = false;
  }
  ...
}