从父组件角度更改子组件样式,但不全局更改

时间:2020-03-17 15:58:34

标签: css angular angular-material components encapsulation

我已经基于<nextgen-table></nextgen-table>(角度材料)创建了一个共享组件(Mat-table)。在项目中使用此组件时,发现我需要更改表列的行为(宽度)。

我已经将nextgen-table导出到其他组件中(例如X,Y),其中nextgen-table当然是子组件。

要更改mat-table的特定列的宽度,我必须使用类似以下的内容:

mat-cell:nth-child(1),
mat-header-cell:nth-child(1) {
    flex: 0 0 40%;
    text-align: left;
} 
mat-cell:nth-child(2),
mat-header-cell:nth-child(2) {
    flex: 0 0 20%;
}

我在X.component.css中实现的上述CSS代码,由于封装原因,无法正常工作。

经过一番搜索,我发现仅在encapsulation: ViewEncapsulation.None的组件装饰器中添加x.component.ts即可正常工作的solution。解决方案之后,我从组件X导航到没有实现上述CSS代码的组件Y。但是,组件Y具有前两列,因为我只想要组件X,但不知何故组件Y也具有我不希望用于组件Y的东西。

所以我的问题是如何从仅适用于父组件而不适用于其他组件的父组件更新nextgen-table的样式。

我也尝试使用

:host(mat-cell:nth-child(1)){
  flex: 0 0 40%;
  text-align: left;
}

:host(mat-header-cell:nth-child(1)) {
    flex: 0 0 40%;
    text-align: left;
}

但没有任何反应/改变。

预先感谢您的帮助

2 个答案:

答案 0 :(得分:2)

您可以使用::ng-deep pseudo class来专门针对子元素,而无需更改整个组件的视图封装(这意味着其所有规则都会泄漏)。

注意::ng-deep自从几个主要版本以来已被标记为不推荐使用,但是只有在有解决方法时,它们才会删除suppoprt。

parentX.html

<div class="compContainer">
    <nextgen-table></nextgen-table>
</div>

parentX.scss

::ng-deep .compContainer nextgen-table
{
    mat-cell:nth-child(1),
    mat-header-cell:nth-child(1) {
        flex: 0 0 40%;
        text-align: left;
    } 
    mat-cell:nth-child(2),
    mat-header-cell:nth-child(2) {
        flex: 0 0 20%;
    }
}

您还可以将CSS规则添加到全局style.scss文件中。

//Rules for parent X
app-parent-componentX .compContainer nextgen-table
{
    mat-cell...
}

//Rules for a parent Y
app-parent-componentY .compContainer nextgen-table
{
    mat-cell...
}

答案 1 :(得分:2)

您需要做的就是在X或Y组件中同时使用:host::ng-deep伪类选择器。

这是工作中的demo

这是快速解释。

<nextgen-table>内部编写的

样式(可以说nextgen-table.component.css)通过为每种样式添加特定的属性而被角度封装。也就是说,如果您写过类似的内容,

.mat-header-cell{
    background-color: #ff0000;
}

然后它变成类似

.mat-header-cell[_ngcontent-c29]
    background-color: #ff0000;
}

所以我们要做的就是在组件X或组件Y中覆盖此样式。

我们有::ng-deep个伪选择器,它将防止angular封装出组件的css。

但是使用::ng-deep也会将我们的CSS泄漏到父组件上。因此,为防止这种情况,我们需要封装::ng-deep样式。为此,我们可以使用:host伪选择器。

因此,如果我们在组件X中编写以下CSS,

:host ::ng-deep .x-table .mat-header-cell{
  background-color: lightblue;
}

然后它将变成类似

[_nghost-c82] .x-table .mat-header-cell {
    background-color: lightblue;
}

现在,以上关于CSS选择的优先级高于表组件.mat-header-cell[_ngcontent-c29]中编写的样式。

这就是我们可以在任何父组件中覆盖子组件样式的方式。 我希望这会有所帮助。

更新: 如您在Angular's official docs中所见,::ng-deep已过时。

不推荐使用穿刺后代组合器,并且支持 从主要的浏览器和工具中删除。因此,我们计划放弃 在Angular中提供支持(适用于/ deep /,>>>和:: ng-deep的全部3种)。直到 那么:: ng-deep应该是首选,以便与 工具。

因此,如果您不想再依赖::ng-deep

您可以在已经尝试过的ViewEncapsulation.None表组件中使用<nextgen-table>Demo here

为防止样式渗入其他组件,您可以通过在所有样式之前添加选择器来确定表格样式的范围。

nextgen-table .mat-header-cell{
    background-color: #ff0000;
}

,然后对X组件执行相同的操作。

  • 使用ViewEncapsulation.None禁用视图封装
  • 然后通过编写比表的实际样式具有更高特异性的样式来覆盖表组件上的样式。

在X组件中禁用封装

@Component({
  selector: "app-x",
  styleUrls: ["x.component.css"],
  templateUrl: "x.component.html",
  encapsulation: ViewEncapsulation.None
})
export class XComponent {

}

然后在x.compoent.css中覆盖表的组件样式

app-x nextgen-table .mat-header-cell{
  background-color: lightblue;
}

如果您不想禁用视图封装,则可以将样式直接写入全局样式表styles.css

请记住,这都是关于覆盖和限定样式的。