Angular - 如何在销毁组件后从<head>中删除<style>元素

Hrv*_*cic 11 angular

注意:我在Angular 5和Angular 6中都尝试了这个例子.

问题

如果'encapsulation: ViewEncapsulation.None'在Angular组件上使用,则<style>元素将附加到<head>何时显示组件.<style>即使在组件被销毁之后,该元素也永远不会被删除.这是问题所在.随着展示的组件越来越多,其中的<style>元素越来越多<head>.最终,当存在针对相同html元素的全局css规则时,这会导致冲突,例如body,根据我的示例.<style> 即使最后一个<style>块属于不再存在的组件,也只使用最后附加的块中的CSS .

头部样式

我想看到一个适当的解决方案,从DOM中删除<style>一些组件附带的元素.例如,当onDestoy触发组件的功能时进行清理.

我是Angular的新手,我偶然发现了这个有趣的行为.很高兴知道是否有一个简单的解决方法.


示例:https: //stackblitz.com/edit/angular-ukkecu

角度的例子

在我的应用程序中,我有3个包装器组件,它们将是我的应用程序的根元素.当时只会显示一个.显示的组件将确定整个网站的主题.它应该包括全局样式,更具体地说是全局样式(主题)的专用变体.因此他们都有'encapsulation: ViewEncapsulation.None'.每种全局样式都有自己编译的bootstrap变体和其他基于SASS变量的外部插件.因此,在这里进行封装是没有选择的,这些是全局样式和插件.

该解决方案仅在第一次正常工作,直到显示其他组件并将<style>元素附加到<head>.之后,仅使用最后使用的组件中的样式,因为它<style>最后一个并覆盖任何以前的样式.


可能的解决方案

似乎唯一的解决方案是重新加载页面,或者不使用组件来切换全局主题.

ben*_*oam 13

忘记encapsulation您的情况,它无法帮助您满足您的要求。而是使用共享服务,我们称之为style-service,它将添加/删除文档头中的样式节点。

您将使用style-service on函数添加样式,而不是stylesUrls@Component装饰器的 中添加您的 css 样式,这会将样式节点添加到文档头部。一旦组件在功能上被破坏,您将使用style-service删除样式,这将从文档头中删除样式节点。ngOnInitngOnDestroy

话不多说,让我们看一些代码:

style.service.ts

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

@Injectable()
export class StyleService {
  private stylesMap: Map<any, Node> = new Map();
  private host: Node;

  constructor() {
    this.host = document.head;
  }

  private createStyleNode(content: string): Node {
    const styleEl = document.createElement('style');
    styleEl.textContent = content;
    return styleEl;
  }

  addStyle(key: any, style: string): void {
    const styleEl = this.createStyleNode(style);
    this.stylesMap.set(key, styleEl);
    this.host.appendChild(styleEl);
  }

  removeStyle(key: any): void {
    const styleEl = this.stylesMap.get(key);
    if (styleEl) {
      this.stylesMap.delete(key);
      this.host.removeChild(styleEl);
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

WrapperVariantRedComponent(来自您的演示)

import { Component, OnInit, OnDestroy, Renderer2 } from '@angular/core';

import { StyleService } from '../style.service';

declare const require: any;

@Component({
  selector: 'app-wrapper-variant-red',
  templateUrl: './wrapper-variant-red.component.html',
  styleUrls: [ './wrapper-variant-red.component.css']
})
export class WrapperVariantRedComponent implements OnInit, OnDestroy {

  constructor(private styleService: StyleService) { }

  ngOnInit() {
    this.styleService.addStyle('red-theme', require('../../theme/global-theme-variant-red.css'));
  }

  ngOnDestroy() {
    this.styleService.removeStyle('red-theme');
  }

}
Run Code Online (Sandbox Code Playgroud)

来自您的 StackBlitz 示例的工作(分叉)演示