【问题标题】:Angular Create Style Tag in View Template?Angular 在视图模板中创建样式标签?
【发布时间】:2020-04-14 10:02:03
【问题描述】:

我想创建一个通用的 html 片段组件。我们的想法是我们可以将 html 片段存储在某处的数据库中,以及应该应用于它们的样式。

我可以轻松设置 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>

工作不正常。有没有办法做到这一点?

【问题讨论】:

  • 我已经搜索了一段时间,您会找到的方法要么过于指定,如 [style.color]="blue",要么是具有破坏 AOT 的动态组件等的顶级解决方案。现在(使用 shadow dom)显然是一种 hack,可以按照他们一直以来的方式做事。所以,一个快速的技巧,如果你将样式标签作为一个字符串添加到你的 html 字符串中,它应该呈现。但我会考虑另一种方法,甚至可能是另一种不基于组件的框架。

标签: angular angular2-template


【解决方案1】:

它不能在模板本身中完成(Angular 模板编译器不允许这样做,只会删除任何&lt;style&gt; 标签),但可以在组件内以编程方式完成:

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

【讨论】:

  • 这行得通,但我必须在样式中添加!important
【解决方案2】:

默认情况下,Angular 会吞噬 &lt;style&gt; 元素并将它们放入默认的 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 之前确保内容是安全的。

【讨论】:

    【解决方案3】:

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

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

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

    无论如何,除了序言之外,您可以通过将 &lt;style&gt; 标签放在 &lt;svg&gt; 标签中来防止删除它们,例如:

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

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

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

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

    【讨论】:

      【解决方案4】:

      style 元素应该在 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);
          }
        }
      

      【讨论】:

      • 虽然许多人考虑将
      猜你喜欢
      • 2016-09-02
      • 1970-01-01
      • 2019-10-21
      • 1970-01-01
      • 2020-10-26
      • 2016-04-05
      • 1970-01-01
      • 1970-01-01
      • 2018-06-17
      相关资源
      最近更新 更多