Angular 2 - innerHTML-стиль

Я получаю фрагменты HTML-кодов из HTTP-вызовов. Я помещаю блоки HTML в переменную и вставляю ее на свою страницу с помощью [innerHTML], но не могу стилизовать вставленный блок HTML. У кого-нибудь есть предложения, как мне этого добиться?

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

HTML-код, который я хочу оформить, представляет собой блок, содержащийся в переменной "calendar".

13 ответов

Решение

обновление 2::slotted

::slotted теперь поддерживается всеми новыми браузерами и может использоваться с `ViewEncapsulation.ShadowDom

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

обновление 1::ng-deep

/deep/ устарела и заменена ::ng-deep,

::ng-deep также уже помечен как устаревший, но пока нет замены.

когда ViewEncapsulation.Native правильно поддерживается всеми браузерами и поддерживает стилизацию через теневые границы DOM, ::ng-deep вероятно будет прекращено.

оригинал

Angular добавляет все виды CSS-классов в HTML-код, добавляемый в DOM для эмуляции теневой DOM-инкапсуляции CSS, чтобы предотвратить появление стилей в компонентах. Angular также переписывает CSS, который вы добавляете, для соответствия этим добавленным классам. Для HTML добавлено с помощью [innerHTML] эти классы не добавляются, и переписанный CSS не совпадает.

В качестве обходного пути попробуйте

  • для CSS добавлен в компонент
/* :host /deep/ mySelector { */
:host ::ng-deep mySelector { 
  background-color: blue;
}
  • для CSS добавлен в index.html
/* body /deep/ mySelector { */
body ::ng-deep mySelector {
  background-color: green;
}

>>> (и эквивалент/deep/ но /deep/ лучше работает с SASS) и ::shadow были добавлены в 2.0.0-бета.10. Они похожи на CSS-комбинаторы теневого DOM (которые устарели) и работают только с encapsulation: ViewEncapsulation.Emulated который используется по умолчанию в Angular2. Они, вероятно, также работают с ViewEncapsulation.None но тогда игнорируются только потому, что они не нужны. Эти комбинаторы являются лишь промежуточным решением, пока не поддерживаются более продвинутые функции для многокомпонентного стиля.

Другой подход заключается в использовании

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

для всех компонентов, которые блокируют ваш CSS (зависит от того, где вы добавляете CSS и где находится HTML, который вы хотите стилизовать - это могут быть все компоненты в вашем приложении)

Обновить

Пример Плункер

Вам нужно следовать простому решению:

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

constructor(private sanitizer: DomSanitizer){}

transformYourHtml(htmlTextWithStyle) {
    return this.sanitizer.bypassSecurityTrustHtml(htmlTextWithStyle);
}

Мы часто загружаем контент из нашей CMS как [innerHTML]="content.title". Помещаем необходимые классы в корень приложенияstyles.scssфайл, а не в scss-файле компонента. Наша CMS намеренно удаляет встроенные стили, поэтому мы должны подготовить классы, которые автор может использовать в своем контенте. Помните использование{{content.title}} в шаблоне не будет отображать html из содержимого.

Если вы пытаетесь стилизовать динамически добавленные элементы HTML внутри компонента Angular, это может быть полезно:

// 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(), '')
}

Я предполагаю, что соглашение для этого атрибута не гарантируется стабильным между версиями Angular, поэтому при обновлении до новой версии Angular могут возникнуть проблемы с этим решением (хотя обновление этого решения, вероятно, будет тривиальным в этом дело).

Используйте метод ниже, чтобы разрешить стили CSS в innerhtml.

      import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
.
.
.
.
html: SafeHtml;

constructor(protected _sanitizer: DomSanitizer) {
   this.html = this._sanitizer.bypassSecurityTrustHtml(`
        <html>
        <head></head>
        <body>
           <div style="display:flex; color: blue;">
              <div>
                 <h1>Hello World..!!!!!</h1>
              </div>
           </div>
        </body>
        </html>`);
}

Пример кода stackblitz

Или используйте метод ниже, чтобы писать прямо в HTML.https://gist.github.com/klihelp/4dcac910124409fa7bd20f230818c8d1

Самый простой и понятный - использовать файл глобальных стилей, расположенный в папке src проекта angular.

Предполагая, что селектор компонентов: app-my-component

Добавьте класс к элементу, содержащему содержимое innerHtml в шаблоне app-my-component:

      <div class="innerhtml-class" [innerHTML]="variable.innerHtml"></div>

Добавьте в файл глобальных стилей:

      app-my-component { 
 .innerhtml-class { 
   declaration goes here 
 } 
}

Рекомендуемая версия Günter Zöchbauer работает нормально, но мне нужно сделать дополнение. В моем случае у меня был нестилизованный html-элемент, и я не знал, как его стилизовать. Поэтому я разработал трубу, чтобы добавить ей стиля.

import { Pipe, PipeTransform } from '@angular/core';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';


@Pipe({
    name: 'StyleClass'
})
export class StyleClassPipe implements PipeTransform {

    constructor(private sanitizer: DomSanitizer) { }
    transform(html: any, styleSelector: any, styleValue: any): SafeHtml {
        const style = ` style = "${styleSelector}: ${styleValue};"`;
        const indexPosition = html.indexOf('>');
        const newHtml = [html.slice(0, indexPosition), style, html.slice(indexPosition)].join('');
        return this.sanitizer.bypassSecurityTrustHtml(newHtml);
    }

}

Затем вы можете добавить стиль к любому html-элементу следующим образом:

<span [innerhtml]="Variable | StyleClass: 'margin': '0'"> </span>

С участием:

Variable = '<p> Test </p>

Альтернативой использованию классов CSS внутри [innerHTML] является объявление их в глобальном файле, например,styles.scss. Этот файл указан в angular.json.

              "styles": [
          "./node_modules/flexboxgrid/dist/flexboxgrid.min.css",
          "src/styles.scss"
        ],

Для всех, кто хочет, просто применяет определенный стиль к innerHTML:

Следуйте инструкциям по созданию безопасного канала HTML

И вы можете объединить свою HTML-строку со стилем CSS следующим образом:

      return this.sanitizer.bypassSecurityTrustHtml(value+='<style type="text/css">.image img { width: 100% }</style>');

Этот value из преобразования (значение, ... аргументы)

Я пошел this.sanitizer.bypassSecurityTrustHtml() route изначально и установил инкапсуляцию на, но возникли 2 проблемы:

  1. ViewEncapsulation.NONE вызывал другие проблемы со стилем в моем компоненте
  2. Мой "безопасный" html не работал с переменными css, т.е. var(- синий)

Это сработало для меня (без необходимости ничего менять): InsertAdjacentHTML

Шаблон:

      <div id=template></div>

Код:

      ngOnInit() {
  const d1 = document.getElementById('template');
  d1.insertAdjacentHTML('afterbegin', `<span style="color: var(--blue)">hello</span>`);
}

Отказ от ответственности : в моем случае я разбирал html из файлов конфигурации. Вы бы не хотели идти по этому пути с введенным пользователем html.

Использование встроенных переменных CSS является альтернативным решением, если у вас ограниченное количество динамических стилей.

Т.е.

      // file.ts
someVarWithHtml = 'Hello <span class="dynamic">World</span>';

// file.ng.html
<div [style]="'--my-var: ' + value"
     [innerHTML]="someVarWithHtml"></div>

// style.css
.dynamic {
  background: var(--my-var);
}

Используйте метод ниже, чтобы разрешить стили css в innerhtml.

      import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
.
.
.
.
html: SafeHtml;

constructor(protected _sanitizer: DomSanitizer) {
   this.html = this._sanitizer.bypassSecurityTrustHtml(`
        <html>
        <head></head>
        <body>
           <div style="display:flex; color: blue;">
              <div>
                 <h1>Hello World..!!!!!</h1>
              </div>
           </div>
        </body>
        </html>`);
}

Пример кода stackblitz

Или используйте метод ниже, чтобы писать прямо в html. https://gist.github.com/klihelp/4dcac910124409fa7bd20f230818c8d1

Если вы используете sass в качестве препроцессора стиля, вы можете вернуться к собственному компилятору Sass для зависимости от разработчиков:

npm install node-sass --save-dev

Чтобы вы могли продолжать использовать /deep/ для разработки.

Другие вопросы по тегам