Angular 2 - styling innerHTML

170

Otrzymuję fragmenty kodów HTML z wywołań HTTP. Umieszczam bloki HTML w zmiennej i wstawiam je na mojej stronie za pomocą [innerHTML], ale nie mogę nadać stylu wstawionemu blokowi HTML. Czy ktoś ma jakieś sugestie, jak mogę to osiągnąć?

@Component({selector: 'calendar',
template: '<div [innerHTML]="calendar"></div>',
providers:[HomeService], 
styles: [` 
h3 {color:red;}
`})

HTML, do którego chcę nadać styl, to blok zawarty w zmiennej „calendar”.

Jakob Svenningsson
źródło
Styl skąd? Z poziomu komponentu czy ze stylów dodanych do index.html?
Günter Zöchbauer
co masz na myśli can not style the inserted HTML block? Pokaż nam, co dla tego zrobiliśmy, za pomocą małego fragmentu kodu.
micronyks
Zaktualizowałem swój post fragmentem kodu! :) dzięki
Jakob Svenningsson
1
Dodałem link Plunker do mojej odpowiedzi
Günter Zöchbauer
@ GünterZöchbauer co jeśli kody HTML mają wbudowany css? jak to będzie renderowane?
iniravpatel

Odpowiedzi:

320

aktualizacja 2 ::slotted

::slotted jest teraz obsługiwany przez wszystkie nowe przeglądarki i może być używany z ViewEncapsulation.ShadowDom

https://developer.mozilla.org/en-US/docs/Web/CSS/::slotted

aktualizacja 1 :: ng-deep

/deep/został wycofany i zastąpiony przez ::ng-deep.

::ng-deep jest już oznaczony jako przestarzały, ale nie ma jeszcze dostępnego zamiennika.

Kiedy ViewEncapsulation.Nativejest prawidłowo obsługiwany przez wszystkie przeglądarki i obsługuje style poza granicami Shadow DOM, ::ng-deepprawdopodobnie zostanie wycofany.

oryginalny

Angular dodaje wszystkie rodzaje klas CSS do kodu HTML, który dodaje do DOM, aby emulować enkapsulację CSS shadow DOM, aby zapobiec pojawianiu się i wylewaniu stylów z komponentów. Angular również przepisuje dodany CSS, aby pasował do tych dodanych klas. Dla HTML dodanego przy użyciu[innerHTML] tych klas nie są one dodawane, a przepisany CSS nie pasuje.

Aby obejść ten problem, spróbuj

  • dla CSS dodanego do komponentu
/* :host /deep/ mySelector { */
:host ::ng-deep mySelector { 
  background-color: blue;
}
  • dla CSS dodanych do index.html
/* body /deep/ mySelector { */
body ::ng-deep mySelector {
  background-color: green;
}

>>>(i odpowiednik, /deep/ale /deep/działa lepiej z SASS) i ::shadowzostały dodane w wersji 2.0.0-beta.10. Są podobne do kombinatorów Shadow DOM CSS (które są przestarzałe) i działają tylko z encapsulation: ViewEncapsulation.Emulatedtymi, które są domyślne w Angular2. Prawdopodobnie też z nimi współpracująViewEncapsulation.None ale są wtedy ignorowane tylko dlatego, że nie są konieczne. Te kombinatory są tylko rozwiązaniem pośrednim, dopóki nie będą obsługiwane bardziej zaawansowane funkcje stylizacji między komponentami.

Innym podejściem jest użycie

@Component({
  ...
  encapsulation: ViewEncapsulation.None,
})

dla wszystkich komponentów, które blokują CSS (w zależności od tego, gdzie dodasz CSS i gdzie HTML chcesz nadać styl - mogą to być wszystkie komponenty w Twojej aplikacji)

Aktualizacja

Przykład Plunker

Günter Zöchbauer
źródło
6
Uwaga dla każdego, to nie działa ani z node-sass, ani ze styleUrl. Tylko w stylach: [...]
thouliha
12
Z SASS /deep/zamiast>>>
Günter Zöchbauer
1
Nie możesz mieć dyrektyw ani składników w treści dodanej za pomocąinneeHTML
Günter Zöchbauer
1
Jeśli kod HTML dostarczony przez wywołanie HTTP jest duży i ma wbudowany css, jak to będzie możliwe, ponieważ nie mam predefiniowanych stylów, otrzymuję go tylko z wbudowanego css @ GünterZöchbauer
iniravpatel
1
Uratowałem dzień w Angular 8! Dzięki. Trudno odpowiedzieć poprawnie na pytanie, aby znaleźć tę odpowiedź!
Pianoman
12

Prostym rozwiązaniem, którego musisz przestrzegać, jest

import { DomSanitizer } from '@angular/platform-browser';

constructor(private sanitizer: DomSanitizer){}

transformYourHtml(htmlTextWithStyle) {
    return this.sanitizer.bypassSecurityTrustHtml(htmlTextWithStyle);
}
Sahil Ralkar
źródło
2

Jeśli próbujesz stylizować dynamicznie dodawane elementy HTML wewnątrz składnika Angular, może być to pomocne:

// inside component class...

constructor(private hostRef: ElementRef) { }

getContentAttr(): string {
  const attrs = this.hostRef.nativeElement.attributes
  for (let i = 0, l = attrs.length; i < l; i++) {
    if (attrs[i].name.startsWith('_nghost-c')) {
      return `_ngcontent-c${attrs[i].name.substring(9)}`
    }
  }
}

ngAfterViewInit() {
  // dynamically add HTML element
  dynamicallyAddedHtmlElement.setAttribute(this.getContentAttr(), '')
}

Domyślam się, że konwencja dla tego atrybutu nie jest gwarantowana jako stabilna między wersjami Angulara, więc można napotkać problemy z tym rozwiązaniem podczas aktualizacji do nowej wersji Angulara (chociaż aktualizacja tego rozwiązania byłaby prawdopodobnie trywialna w tym walizka).

Trevor
źródło
2

Często pobieramy treści z naszego CMS jako [innerHTML]="content.title". styles.scssUmieszczamy niezbędne klasy w głównym pliku aplikacji, a nie w pliku scss komponentu. Nasz CMS celowo usuwa style in-line, więc musimy mieć przygotowane klasy, które autor może wykorzystać w ich treści. Pamiętaj, że użycie {{content.title}}w szablonie nie spowoduje renderowania html z treści.

Lyfo
źródło
-3

Jeśli używasz Sass jako preprocesora stylu, możesz przełączyć się z powrotem na natywny kompilator Sass w celu uzyskania zależności od deweloperów:

npm install node-sass --save-dev

Abyś mógł nadal używać / deep / do programowania.

Brian Lu
źródło