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

时间:2017-05-15 20:46:15

标签: angular angular2-template

我想创建一个通用的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;
}

以下是视图模板:

<style [innerHTML]="styleContent"></style>
<div [innerHTML]="htmlContent"></div>

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

 <htmlFragment [htmlContent]='dHtml' [styleContent]="sHtml"></htmlFragment>

其中:

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

html片段在这里正确注入:

<div [innerHTML]="htmlContent"></div>

但是这里的样式元素:

 <style [innerHTML]="styleContent"></style>

无效。有没有办法做到这一点?

4 个答案:

答案 0 :(得分:9)

它不能在模板本身中完成(Angular模板编译器不允许它,并且只删除任何{ "one": "two", "key": "value" } 标记),但它可以在组件中以编程方式完成:

<style>

答案 1 :(得分:1)

默认情况下,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>
    `);
  }
}

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

答案 2 :(得分:1)

与OP有关,尽管为了完整起见,我不建议使用下面的旁路(或该线程中的任何其他旁路)。推荐的解决方案是将.scss / .css / .html分别存储在数据库中-运行服务器端gulp任务并编译模块并延迟加载它们(然后支持shadow-dom,没有安全问题,还有很多通用性)。

在任何情况下,都有很多理由说明为什么将样式(通过注入或其他方式)放入模板中是一种不良做法,包括违反封装等。

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

无论如何,除了前言之外,您还可以通过将<svg>标记放置在<svg> <style> .global-style-x { transform: rotate({{someAngleComputation}}deg); } </style> </svg> <button class="global-style-x"> </button> 标记中来防止其被移除,例如:

[innerHTML]='styleTag | keepHtml"

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

  • 我提到的那个很可能会被将来的模板编译器捕获/清除
  • @ebrehault解决方案与shadow-dom不兼容,并且在事件处理程序之外对dom进行更改,并且在销毁组件时也不会将其删除。此外,它不会按照OP的要求与模板一起存储。
  • @ZachDahl的解决方案不太可能破解,可以转换为管道版本(ala [attr.style]="style | keepStyle")。
  • @JuliaPassynkova的内联样式解决方案也不太可能打破,尽管这意味着无法使用任何类,不进行级联并且用途非常有限。

@ZachDahl和@JuliaPassynkova解决方案,无论是否使用[innerHTML]="yourStyleTag | keepHTML"或{{1}}之类的管道-...都绕过安全设备,并可能造成注入攻击的威胁。

答案 3 :(得分:0)

样式元素应该在HEAD中。

您可以使用[attr.style]

将样式从字符串应用于html元素
  @Component({
    selector: 'my-app',
    template: `
      <div>
        <h2 [attr.style]="style">Hello {{name}}</h2>
      </div>
    `,
  })
  export class App {
    style;
    myStyleStr = 'color:blue';

    name:string;
    constructor(private sanitizer: DomSanitizer) {
      this.name = `Angular! v${VERSION.full}`;
      this.style = sanitizer.bypassSecurityTrustStyle(this.myStyleStr);
    }
  }