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

时间:2018-05-12 22:22:48

标签: angular

&#XA;

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

&#xA;
&#xA;&#xA;

问题

&#xA; &#xA;

如果在Angular组件上使用'封装:ViewEncapsulation.None'&lt; style&gt; 元素将附加到&lt; head&gt; 何时显示组件。即使在组件被销毁之后,&lt; style&gt; 元素也永远不会被删除。这是问题。&#xA;随着显示的组件越来越多,&lt; head&gt; 中有越来越多的&lt; style&gt; 元素。最终,当存在相同html元素的全局css规则时,这会导致冲突,例如 body ,根据我的例子。只使用最后附加的&lt; style&gt; 块中的CSS,即使最后&lt; style&gt; 块属于不再存在的组件。 / p>&#xA;&#xA;

&#xA;&#xA;

我希望看到一个合适的解决方案,以便从DOM与某些组件一起出现的&lt; style&gt; 元素。例如。当触发组件中的 onDestoy 函数时清理。

&#xA;&#xA;

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

&#xA;&#xA;
&#xA;&#xA;

示例

&#xA;&#xA ;

示例:&#xA; https://stackblitz.com/edit/angular-ukkecu

&#xA;&#xA;

&#xA;&#xA;

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

&#xA;&#xA;

解决方案只在第一次正常工作,直到显示其他组件并且&lt; style&gt; 元素附加到&lt; head&gt; 。之后,仅使用最后使用的组件中的样式,因为它的&lt; style&gt; 排在最后并覆盖以前的任何样式。

&#xA;&#xA;
& #xA;&#xA;

可能的解决方案

&#xA;&#xA;

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

&#XA;

2 个答案:

答案 0 :(得分:4)

忘记您的情况encapsulation,这对您的要求无济于事。取而代之的是使用共享服务,将其称为 style-service ,它将在文档头中添加/删除样式节点。

您无需在stylesUrls装饰器的@Component中添加CSS样式,而是使用ngOnInit函数上的 style-service 来添加样式,这会将样式节点添加到文档头。使用ngOnDestroy函数销毁组件后,您将使用 style-service 删除样式,这将从文档头删除样式节点。

足够了,让我们看一些代码:

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);
    }
  }
}

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');
  }

}

从StackBlitz示例中工作(派生)DEMO

答案 1 :(得分:0)

不知道解决方案,但您正在使用它的组件的ViewEncapsulation.NONE属性不是默认属性默认值是ViewEncapsulation.Emulated我想它为组件中的每个标记提供唯一ID因此解决了这些类型的问题然后你为什么使用ViewEncapsulation.NONE ???