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

问题描述

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

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

@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,但是在离开页面时将其删除?”。

解决方法

解决了!通过DomSanitizer.bypassSecurityTrustHtml

这里是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>

这是有效的,因为CSS位于HTML内,因此当组件被销毁时,也是如此。 (由于bypassSecurityTrustHtml,Angular不会尝试修改它)

,

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

1。单独的页面

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

2。客户端CSS渲染

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

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

当您访问需要激活该页面的页面时,只需使用基于模板生成并添加到style的{​​{1}} HTML元素初始化属性。离开给定视图后,组件将检测到该事件并head该元素。如果选择此解决方案,那么最好以更笼统的术语来支持此解决方案,这样一来,如果某些新视图将具有其自定义的全局CSS,那么将来它们很容易集成到您的项目中

3。身体类别

每当要更改样式时,都可以在remove()中添加一些custom-print或从其中删除类。这样,您可以将CSS完全添加到HTML一次,并相应地更改规则,例如:

body

这将是一个很好的解决方案,但您的问题是您也有一个body.custom-print { margin: 30px; } 规则,但我不确定如何使它依赖于正文类或其他一些HTML属性。如果我是你的话,我将为此做很多实验。

4。 iframe分期

您可以避免在主页上放置该CSS,但是会在@page中隐藏一个CSS,将其复制到CSS中,然后将其复制并打印出来。

,

不要改变苹果的整个身体。相反,需要进行一些更改。

  1. 在应用程序组件中,请为您是否在苹果计算机上保存一个布尔值,并将ngClass用作scss中定义的类。

  2. 跟踪您在appComponent中的路线,并相应地设置isApple

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

  4. 添加全局html,主体设置高度为100%,这样您就可以在任何地方看到颜色

  5. 删除苹果中的身体覆盖

所以, 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(删除主体)

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

,

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

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

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