如何不使用已废弃的/deep/覆盖Angular中ng-template生成的ngx-datatable样式
废弃
/deep/语法下的Angular第三方组件动态元素样式覆盖方案 问题根因
Angular默认的视图封装(ViewEncapsulation.Emulated)会给组件内编写的所有CSS选择器自动追加组件专属的_ngcontent-xxx属性选择器,实现样式隔离。而ngx-datatable这类第三方组件内部动态生成的、不在当前组件DOM树内的元素(比如自动套在ng-template外层的.datatable-row-detail容器),身上没有当前组件的_ngcontent-xxx属性标记,因此会出现选择器匹配失效的问题——哪怕加了!important,因为选择器根本没命中目标元素,样式自然无法生效。
之前使用的/deep/语法的作用就是打穿这层封装,让选择器跳过_ngcontent属性的匹配要求,现在该语法废弃后,可以通过以下官方支持的方案实现同等效果。
按推荐优先级排序的最佳实践
方案一:使用::ng-deep伪类(官方合法替代,改动成本最低)
这是Angular官方推荐的/deep/替代方案,不会触发语法废弃警告,适合小范围覆盖少量第三方组件内部元素的场景。
对应现有代码的修改方式:
/* 替换原有的 /deep/ 写法 */ ::ng-deep .datatable-body-row { border-bottom: 1px solid #000; } ::ng-deep .datatable-row-detail { width: 600px !important; }
注意事项:
- 必须将带
::ng-deep的样式写在当前使用ngx-datatable的组件的私有样式文件中,不要放在全局根样式文件里,否则会让样式失去隔离作用,污染全应用范围内的同class元素。 - 不要给
::ng-deep加多余的父选择器,避免缩小打穿范围导致匹配失效。
方案二:调整组件视图封装模式(适合大范围覆盖第三方组件的场景)
如果当前页面需要批量修改大量ngx-datatable的内部样式,可以在组件元数据中修改视图封装模式,让组件内编写的样式自动变为全局样式,省去写大量::ng-deep的麻烦。
组件配置代码示例:
import { Component, ViewEncapsulation } from '@angular/core'; @Component({ selector: 'app-your-datatable-page', templateUrl: './xxx.component.html', styleUrls: ['./xxx.component.css'], // 将默认的模拟视图封装改为无封装 encapsulation: ViewEncapsulation.None })
此时编写CSS不需要再加::ng-deep,但为了避免全局样式污染其他页面,需要给所有覆盖的第三方样式加上当前组件的根元素选择器作为范围前缀:
/* 以当前组件的选择器做范围限制,仅作用于本页面的datatable */ app-your-datatable-page .datatable-body-row { border-bottom: 1px solid #000; } app-your-datatable-page .datatable-row-detail { width: 600px !important; }
注意事项:
- 该方案影响范围比
::ng-deep大,仅适合需要覆盖大量第三方组件样式的场景,小范围修改优先选方案一。 - 加组件根选择器做范围限制是必须步骤,否则样式会全局生效,导致其他页面用到的datatable被意外覆盖。
常见踩坑提示
- 不要尝试通过给元素加自定义id/类的方式覆盖:
.datatable-row-detail是第三方组件在你写的ng-template外层自动生成的包裹容器,你写的ng-template内部的DOM类名,根本作用不到这层容器上,额外加类属于无效操作。 - 不要把
::ng-deep写在全局样式文件里:写在全局文件中的::ng-deep会完全失去样式作用域限制,导致全应用内所有匹配到的元素都被选中,后期排查样式问题成本极高。 - 不要用通配符选择器大范围打穿样式:比如写
::ng-deep *这类规则,会破坏所有组件的视图封装,带来不可控的样式冲突。
内容的提问来源于stack exchange,提问作者Davut Gürbüz
相关产品推荐
相关产品推荐

