Angular 组件样式的封装(隔离)

Angular 组件样式的封装

样式封装

在html中,无论一个style元素定义在什么地方,其内部的规则都是作用到整个html文档的。
从框架的设计和使用者角度来看,对组件样式都一种封装需求:就是希望针对组件定义的样式只在这个组件内部生效,不影响这个组件之外的元素。
Angular 提供了3种样式封装选项: ViewEncapsulation.Native, ViewEncapsulation.Emulated, ViewEncapsulation.None。 这里有篇介绍文章:https://blog.thoughtram.io/angular/2015/06/29/shadow-dom-strategies-in-angular2.html
可以在定义组件时配置样式封装的方式,例如:

@Component({
  moduleId: module.id,
  selector: '...',
  templateUrl: '....component.html',
  styles: [`...`],
  encapsulation: ViewEncapsulation.None
})

默认的封装方式是 ViewEncapsulation.Emulated, 因为Native会使用shadow Dom, 而shadow Dom 现在并没有得到广泛的浏览器支持。

默认的样式封装带来的问题

默认的封装方式 Emulated ,Angular在运行时会同时对该组件的 html 模板和 css规则进行修改:

  • html模板中的元素都会添加一个属性 _ngcontent-c* , 星号表示一个数字,例如

    <div _ngcontent-c39="" class="topo-container">
    
  • 每条样式规则的每个selector都会加上和上面元素新增的属性对应的属性选择器,例如:

    你定义的规则是这样的:

    div.button-cotainer div.play-button button.fa-arrow-left {
        padding-left: 7px;
        padding-top: 1px;
    }
    

    在浏览器中查看规则,你看到的是这样的:

    div.button-cotainer[_ngcontent-c39]   div.play-button[_ngcontent-c39]   button.fa-arrow-left            [_ngcontent-c39] {
        padding-left: 7px;
        padding-top: 1px;
    }
    

    上面这种对CSS规则的修改,会带来一个问题

  • 由于在JS代码中通过web api(例如 appenChild())动态添加的元素是没有 _ngcontent-c* 这种属性的,导致组件的元数据中的CSS规则无法应用到这种动态添加的元素。

规避这个问题的方法:使用 /deep/ 语法,该语法告知angular不要在 /deep/之后的元素类型上添加属性修饰,例如:选择器 /deep/ p span 经过angular编译后 就是 p span, 当然这样就使得样式具有了全局性,所以最好是结合:host 使用, 例如 :host /deep/ p span。

posted on 2017-04-21 10:11  等待未知  阅读(852)  评论(0编辑  收藏  举报

导航