Angular - Как удалить элемент <style>из <head>после уничтожения компонента - PullRequest
0 голосов
/ 13 мая 2018

Примечание: я пробовал пример как в Angular 5, так и в Angular 6.

Проблема

При использовании 'encapsulation: ViewEncapsulation.None' для углового компонента a <style>элемент будет добавлен к <head> при показе компонента.Элемент <style> никогда не будет удален, даже после уничтожения компонента.Это проблема.Чем больше компонентов отображается, тем больше элементов <style> в <head>.В конечном итоге это вызывает конфликты, когда существуют глобальные правила CSS для того же элемента HTML, например body, как в моем примере.Будет использоваться только CSS из последнего добавленного блока <style>, даже если этот последний блок <style> принадлежит компоненту, который больше не существует.

head styles

Я хотел бы увидеть правильное решение для удаления из DOM элемента <style>, который поставляется вместе с некоторым компонентом.Например, очистка при срабатывании функции onDestoy из компонента.

Я новичок в Angular, и я только что наткнулся на это интересное поведение.Было бы полезно узнать, существует ли простой обходной путь.


Пример

ПРИМЕР: https://stackblitz.com/edit/angular-ukkecu

Angular example

В моем приложении есть 3 компонента-оболочки, которые будут корневым элементом моего приложения.Только один будет показан в то время.Показанный компонент будет определять тему для всего сайта.Он должен включать в себя глобальные стили, в частности, выделенный вариант глобального стиля (темы).По этой причине у всех есть 'encapsulation: ViewEncapsulation.None'.Каждый глобальный стиль имеет свой собственный скомпилированный вариант начальной загрузки и другие внешние плагины на основе переменных SASS.Таким образом, инкапсуляция здесь не подходит, это глобальные стили и плагины.

Решение отлично работает с первого раза, пока не отобразятся другие компоненты и элементы <style> не будут добавлены к <head>.После этого будут использоваться только стили из последнего использованного компонента, поскольку его <style> пришел последним и переопределил все предыдущие стили.


Возможные решения

Кажется, что единственное решение будетбыть, чтобы перезагрузить страницу, или не использовать компоненты для переключения глобальной темы.

Ответы [ 2 ]

0 голосов
/ 24 декабря 2018

Забудьте о encapsulation в вашем случае, это не поможет вам с вашим требованием. Вместо этого используйте общую службу, назовем ее style-service , которая добавит / удалит узлы стиля в заголовке документа.

Вместо добавления ваших стилей CSS в stylesUrls декоратора @Component вы добавите их с помощью функции style-service on ngOnInit, которая добавит узел стиля в заголовок документа. Как только компонент будет уничтожен функцией 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.

0 голосов
/ 13 мая 2018

Не знаю решения, но свойство ViewEncapsulation.NONE используемого вами компонента не является свойством по умолчанию. По умолчанию это ViewEncapsulation.Emulated. Предполагается, что он предоставляет уникальный идентификатор каждому тегу в компоненте проблемы решаются, почему вы используете ViewEncapsulation.NONE ???

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...