Angular:如何添加全局 CSS(例如添加到正文),但仅针对一个特定页面?

Angular: How to add global CSS (e.g. to the body), but only for one specific page?

如何为 Angular 中的 一个 页面添加单独的 CSS?

这是我需要的 CSS,根据 How to remove the URL from the printing page?:

@media print{
    @page{
        margin:0;
    }
    body{
        margin:30px;
    }
}

但是将 CSS 放入带有 ::ng-deepViewEncapsulation.None 的组件中不会有帮助,因为当离开页面时,页面的 CSS没有被删除。

我加了一个Stackblitz,把问题说的很清楚


我想出了一个可能的解决方案,但它不起作用:

  encapsulation: ViewEncapsulation.None

   ...      

  constructor(private renderer: Renderer2) {
    this.renderer.addClass(document.body, 'special-print');
   }

  ngOnDestroy() {
    this.renderer.removeClass(document.body, 'special-print');
  }
  ....
  ....
  ....
  @media print{
    @page{
        margin:0;
    }
    body.special-print{
        margin:30px;
    }
  }

为什么不起作用:

虽然它对 <body> CSS 有帮助,但对 @page CSS 没有帮助。也许这个问题最好总结为“如何添加全局 CSS,但在我们离开页面时将其删除?”。

您可以在组件中添加不同的 css 文件(例如,app-task.component.ts):

@Component({
  selector: 'app-task',
  templateUrl: './app-task.component.html',
  styleUrls: ['./app-task.component.scss', './styles2.scss', './styles3.scss']
})

在此示例中,样式文件与组件位于同一文件夹中,但这不是最佳选择:例如,您必须将文件放在资产中。另外,请注意样式的线程,因为您放置的第一个样式将在第二个样式之前放置(很明显)。

不要从 apple 更改整个 body。相反,需要进行一些更改。

  1. 在app组件中,保存一个boolean表示你是否在apple上,并使用ngClass作为scss中定义的class

  2. 在 appComponent 中跟踪你在哪条路线上,并相应地设置 isApple

  3. 在您的所有 html 周围添加一个 div,以便容器采用全尺寸

  4. 添加全局 html,body 将高度设置为 100%,这样到处都能看到颜色

  5. 移除苹果中的body覆盖

所以, appComponent.ts:

  isApple: Boolean;
  constructor(router: Router) {
    router.events.subscribe(v => {
      if (v instanceof NavigationEnd) {
        this.isApple = v.url === "/apple";
      }
    });
  }

appComponent.html:

<div [ngClass]="{'red':isApple}" class="container">
    <p>
        There are two components: Apple and Banana. Switching between them will show
        the problem.
    </p>

    <router-outlet></router-outlet>
</div>

appComponent.scss


.red {
  background-color: red;
}

.container {
  height: 100%;
}

apple.component.scss(去掉body)

/*Sample "global" CSS, that affects something outside the current component.*/
::ng-deep {
  @media print {
    @page {
      margin: 0;
    }
  }
}

styles.scss(全局)

html, body {
  height: 100%;
}

一共可以看到这个at this Stackblitz link

Angular 正在进行客户端呈现,这是个坏消息,因为您没有单独的页面。不过,您有几种可能的解决方案:

1。单独的页面

您可以创建另一个包含或不包含 Angular 的页面,其中包括您需要的 CSS 并加载该页面。在实现此目的的最简单方法中,其他页面将具有不同的 URL。如果您不喜欢使用不同的 URL,那么您可以隐藏页面的内容并在 iframe 中显示其他页面。诚然,这将是一个 hacky 解决方案,但它是一个解决方案。

2。客户端 CSS 渲染

您可以拥有一个控制全局 CSS 规则的组件,而不是仅仅加载 CSS,并与您的视图名称相匹配。您会将模板值呈现为 属性,例如:

@media print{
    @page{
        margin:0;
    }
    body{
        margin:30px;
    }
}

当你访问需要激活的页面时,你只需初始化一个 属性 和一个基于模板生成并添加的 style HTML 元素至 head。离开给定视图后,您的组件将检测到该事件并 remove() 该元素。如果你选择这个解决方案,那么确保你在更一般的条款上支持它是明智的,这样如果一些新的视图将有他们的自定义全局 CSS,那么它们将很容易集成到你的未来的项目。

3。正文 classes

您可以 add/remove 一些 custom-print 或任何 class to/from body 每当要更改样式时。这样您就可以将 CSS 添加到您的 HTML 并相应地更改规则,例如:

body.custom-print {
    margin: 30px;
}

这将是一个很好的解决方案,但你的问题是你也有一个 @page 规则,我不确定你如何使它依赖于 body class es 或其他一些 HTML 属性。如果我是你,我会为此做很多实验。

4。 Iframe 暂存

您可以避免在您的主页中显示 CSS,但会隐藏一个 iframe,您会在其中显示 CSS,并且只需将内容复制到 CSS 加载后,打印出来。

已解决!

我们将 <style> 块直接打印到组件的 HTML 中,因此当组件被移除时,我们的 <style> 块也被移除。 (通常 这行不通,但由于 DomSanitizer.bypassSecurityTrustHtml,Angular 在 运行 优化时不会破坏我们的代码。)

这是一个StackBlitz

首先,新建一个组件来处理工作:

component.ts: (This is all we need. We don't need an HTML or style.css file.)
//Inside  your local component, place this HTML 
//<app-local-css [style]="'body{background:green !important;}'"></app-local-css>
// OR
//<app-local-css [scriptURL]="'/path/to/file.css'"></app-local-css>

@Component({
  selector: "app-local-css",
  template: '<span style="display:none" [innerHTML]="this.safeString"></span>'
})
export class LocalCSSComponent implements OnInit {
  constructor(protected sanitizer: DomSanitizer) {}
  @Input() scriptURL?: string;
  @Input() style?: string;

  safeString: SafeHtml;
  ngOnInit() {
    if (this.scriptURL) {
      let string = '<link rel="stylesheet" type="text/css" href="' + this.scriptURL + '">';
      this.safeString = this.sanitizer.bypassSecurityTrustHtml(string);
    } else if (this.style) {
      let string = '<style type="text/css">' + this.style + "</style>";
      this.safeString = this.sanitizer.bypassSecurityTrustHtml(string);
    }
  }
}

然后这样使用:

mySample.component.html:

<app-local-css [style]="'body{background:green !important;}'"></app-local-css>
// OR
<app-local-css [scriptURL]="'/path/to/file.css'"></app-local-css>