视图模板中的角度创建样式标记?

cob*_*nks 6 angular2-template angular

我想创建一个通用的html片段组件.我们的想法是将html片段存储在db中的某个地方,以及应该应用于它们的样式.

我可以轻松设置innerHtml以将html结构插入到我的视图模板中的基本元素中,但是如何在我的视图模板中动态插入<style>标记?

这就是我所拥有的:

 @Component({
    moduleId: module.id,
    selector: 'htmlFragment',
    styleUrls: ['html-fragment.css'],
    templateUrl:'html-fragment.html'
})

export class HtmlFragmentComponent {

    @Input() htmlContent: string;
    @Input() styleContent: string;
}
Run Code Online (Sandbox Code Playgroud)

这是视图模板:

<style [innerHTML]="styleContent"></style>
<div [innerHTML]="htmlContent"></div>
Run Code Online (Sandbox Code Playgroud)

然后我试着像这样使用它:

 <htmlFragment [htmlContent]='dHtml' [styleContent]="sHtml"></htmlFragment>
Run Code Online (Sandbox Code Playgroud)

哪里:

dHtml: string = '<div>hello this is html<ul><li>bla bla</li><li>bla bla 2</li></ul></div>';
    sHtml: string = 'ul{list-style-type: none;}';
Run Code Online (Sandbox Code Playgroud)

html片段在这里正确注入:

<div [innerHTML]="htmlContent"></div>
Run Code Online (Sandbox Code Playgroud)

但是这里的样式元素:

 <style [innerHTML]="styleContent"></style>
Run Code Online (Sandbox Code Playgroud)

工作不对.有没有办法做到这一点?

ebr*_*ult 15

它不能在模板本身中完成(Angular模板编译器不允许它,并且只删除任何<style>标记),但它可以在组件内以编程方式完成:

ngOnInit() {
  const css = 'a {color: pink;}';
  const head = document.getElementsByTagName('head')[0];
  const style = document.createElement('style');
  style.type = 'text/css';
  style.appendChild(document.createTextNode(css));
  head.appendChild(style);
}
Run Code Online (Sandbox Code Playgroud)


Zac*_*ahl 5

默认情况下,Angular会吞噬<style>元素并将其放入默认的Angular CSS管道中。您可以通过以下方法绕过此方法:

@Component({
  template: `<div [innerHTML]="styles"></div>`
})
export class OutputStyleTagComponent implements OnInit {
  public styles: SafeHtml;

  constructor(
    private sanitizer: DomSanitizer
  ) {}

  ngOnInit() {
    this.styles = this.sanitizer.bypassSecurityTrustHtml(`
      <style>
       .my-styles {
         ...
       }
      </style>
    `);
  }
}
Run Code Online (Sandbox Code Playgroud)

它具有缺点,例如需要包装div容器。您还必须确保您不允许用户在此标记中提交内容,因为它使您容易受到XSS攻击。如果必须,则需要先确保内容安全,然后再将其传递到bypassSecurityTrustHtml中。


Mat*_*win 5

与OP相关,我不推荐以下绕过(或该线程中的任何其他绕过),但为了完整性我将其放在这里。推荐的解决方案是将 .scss / .css / .html 单独存储在数据库中 - 运行服务器端 gulp 任务并编译模块并延迟加载它们(然后支持 Shadow-dom,没有安全问题,等等)的多功能性)。

无论如何,有很多原因可以解释为什么将样式放入模板中(通过注入或其他方式)是一种不好的做法,包括违反封装等。

以这种方式应用的样式是全局应用的样式。这可能比使用keepStyle管道更有利,或者[attr.style]因为它允许角度计算的样式表,!important如果在库或其他地方使用它,则可以在外部使用该样式表进行覆盖。直接应用于style属性的样式不能被外部 CSS 覆盖。

<style>无论如何,除了序言之外,您可以通过将标签放置在标签中来防止删除标签<svg>,例如:

<svg>
  <style>
     .global-style-x {
        transform: rotate({{someAngleComputation}}deg);
     }
  </style>
</svg>

<button class="global-style-x">
</button>
Run Code Online (Sandbox Code Playgroud)

同样,这些在模板中插入样式的方法都不是最佳实践。

  • 我提到的那个可能会被未来的模板编译器捕获/清理
  • @ebrehault 解决方案与 Shadow-dom 不兼容,并且还会在事件处理程序之外对 dom 进行更改,并且当组件被销毁时也不会被删除。此外,它不会按照 OP 的要求与模板一起存储。
  • @ZachDahl 的解决方案不太可能破坏,并且可以变成管道版本(ala [innerHTML]='styleTag | keepHtml")。
  • @JuliaPassynkova 的内联样式解决方案也不太可能被破坏,尽管这意味着不能使用任何类,不能级联,并且实用性非常有限。

@ZachDahl 和 @JuliaPassynkova 解决方案使用或不使用管道(例如[attr.style]="style | keepStyle"or [innerHTML]="yourStyleTag | keepHTML"-...)正在绕过安全设备并造成注入攻击的潜在威胁。