当前位置:   article > 正文

【BUG】解决::ng-deep的定位失败及样式污染问题_::ng-deep 失效

::ng-deep 失效

:host ::ng-deep .ant-modal-body定位失败问题

问题描述

这个问题是在修改nzModal的内置样式过程中遇到的,欲修改内容为 nzModal组件中,content的pading、margin以及nzModal中子组件的样式等

这些修改并不能直接通过官方提供的api进行修改,但也不是通过标题中的:host ::ng-deep .ant-modal-body进行修改的。虽然:host ::ng-deep .ant-modal-body无法生效,但需要先理解这组选择器的含义。

选择器:host ::ng-deep .ant-modal-body由三部分构成::host的官方表述(Angular - 组件样式)是:"每个组件都会关联一个与其组件选择器相匹配的元素。这个元素称为宿主元素,模板会渲染到其中。:host 伪类选择器可用于创建针对宿主元素自身的样式,而不是针对宿主内部的那些元素。"我个人理解是,:host就是本组件的根选择器。一般来说,:host后面还会加上本组件中的其他DOM元素,表示样式限定在本组件样式中。

::ng-deep也是伪选择器,不指代实际的DOM元素,表示选择器的深入关系。在应用中,一般是A ::ng-deep B的形式,表示从父级选择器A开始,逐层递进,样式的最终目标作用点是选择器B。A和B之间可能间隔多层DOM元素。

.ant-modal-body是nzModal中的内部封装的一个class。利用浏览器的开发者工具能观察到,如下所示的红色部分即为.ant-modal-body类。这个类跟普通的DOM元素一样,只要能在css文件中正确选择出来,就能非常方便的修改这个页面。其他封装好的zorro组件也能通过这个方式查看类名。

因此,:host ::ng-deep .ant-modal-body选择器就表示在当前组件中,选择类名为.ant-modal-body的DOM元素。

看起来确实能够解决问题,但实际上并未生效。这说明:host中并没有.ant-modal-body类

第二次尝试 ::ng-deep .ant-modal-body

既然:host中并没有.ant-modal-body,那么去掉:host,直接使用::ng-deep .ant-modal-body. 结果表明已经生效.问题看似已经解决,但是实际上,其他组件中的modal也被渲染了,即污染了别的组件.这是由于::ng-deep左边未赋选择器,则表示在解析后的整个html文件中,寻找类名为.ant-modal-body的目标DOM,但是其他组件中也包含了这个nzModal,因此也有这个类.ant-modal-body . 这显然不符合需求.

因此,需要进一步细化.ant-modal-body的匹配程度.如果能够找到这个组件中.ant-modal-body的父级DOM,并为其特殊命名,最终形成这样的格式"::ng-deep 父级选择器 .ant-modal-body ",应该能解决问题.

第三次尝试 ::ng-deep 父级选择器  .ant-modal-body

这次将整个nz-Modal标签设置类名:class="myClass",设置样式如下:::ng-deep .myClass .ant-modal-body.最后发现,仍然不生效.思路正确,但结果不对,应该是class设置错误.

第四次尝试 ::ng-deep 父级选择器  .ant-modal-body

千辛万苦查阅资料后,大佬(https://github.com/NG-ZORRO/ng-zorro-antd/issues/5955)给出了一个解决方案:设置class方式为:nzClassName="myClass",而不是class="myClass".最后,使用::ng-deep .myClass .ant-modal-body即可成功.

原因分析:为什么host不包含ant-modal-body?
失败原因
:host ::ng-deep .ant-modal-bodyhost不包含ant-modal-body
::ng-deep .ant-modal-body污染其他组件
::ng-deep .myClass .ant-modal-body(其中myClass为普通class)普通class不包含ant-modal-body
::ng-deep .myClass .ant-modal-body(其中myClass为ngClass)成功

上表总结了四次尝试,有几个关键问题值得探究:

为什么host不包含ant-modal-body?

其实host的作用范围是<app-root>(参看css - Modal Dialog of different widths are not applied with :host and :ng-deep - Stack Overflow),这一点可以在浏览器中查看渲染后的html页面,modal与app-root实际上是并列关系,而不是包含关系(下图展示了app-root和modal的位置关系),这与代码中,modal的位置无关.第三次尝试的失败也是这一原因,因为普通class仍属于app-root,那也就不包含ant-modal-body了.

本次BUG使用的示例代码

为演示""ng-deep的渗透作用,定义了两个component:APPComponent和AnotherComponent.如下:

app.component.ts

  1. export class AppComponent {
  2. isVisible = false;
  3. constructor(private modalService: NzModalService) { }
  4. showModal(): void {
  5. this.isVisible = true;
  6. }
  7. handleOk(): void {
  8. this.isVisible = false;
  9. }
  10. handleCancel(): void {
  11. this.isVisible = false;
  12. }
  13. showConfirm(): void {
  14. this.modalService.confirm({
  15. nzTitle: 'Confirm',
  16. nzContent: 'Bla bla ...',
  17. nzOkText: 'OK',
  18. nzCancelText: 'Cancel'
  19. });
  20. }
  21. }

app.component.html

  1. <div class="div-button">
  2. <button nz-button nzType="primary" (click)="showModal()">AnotherModal</button>
  3. <nz-modal [(nzVisible)]="isVisible" nzTitle="Modal" nzOkText="Ok" nzCancelText="Cancel" (nzOnOk)="handleOk()"
  4. (nzOnCancel)="handleCancel()">
  5. <ng-container *nzModalContent>
  6. <p>Bla bla ...</p>
  7. <p>Bla bla ...</p>
  8. <p>Bla bla ...</p>
  9. </ng-container>
  10. </nz-modal>
  11. </div>
  12. <br />

app.component.less

  1. ::ng-deep .myClass .ant-modal-body {
  2. padding: 0;
  3. height: 500px;
  4. width: 100%;
  5. background-color: red;
  6. }
  7. :host {
  8. font-size: 28px;
  9. }

another.component.ts

  1. export class AnotherComponent {
  2. isVisible = false;
  3. constructor(private modalService: NzModalService) { }
  4. showModal(): void {
  5. this.isVisible = true;
  6. }
  7. handleOk(): void {
  8. this.isVisible = false;
  9. }
  10. handleCancel(): void {
  11. this.isVisible = false;
  12. }
  13. showConfirm(): void {
  14. this.modalService.confirm({
  15. nzTitle: 'Confirm',
  16. nzContent: 'Bla bla ...',
  17. nzOkText: 'OK',
  18. nzCancelText: 'Cancel'
  19. });
  20. }
  21. }

another.component.html

  1. <div class="div-button">
  2. <button nz-button nzType="primary" (click)="showModal()">AnotherModal</button>
  3. <nz-modal [(nzVisible)]="isVisible" nzTitle="Modal" nzOkText="Ok" nzCancelText="Cancel" (nzOnOk)="handleOk()"
  4. (nzOnCancel)="handleCancel()">
  5. <ng-container *nzModalContent>
  6. <p>Bla bla ...</p>
  7. <p>Bla bla ...</p>
  8. <p>Bla bla ...</p>
  9. </ng-container>
  10. </nz-modal>
  11. </div>
  12. <br />

another.component.less为空

ERROR Error: NG0100: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'false'. Current value: 'true'. Expression location: UserManageComponent component.

翻译过来,就表示angular在检查了相关属性后,又变更了这个属性值或变量值.

这个报错对功能暂时没有影响,报错来源:同一个页面先后两次调用同一个modal,分别用来新增和编辑.当先点击编辑,再点击新增时,就会报错.这主要是由于,编辑时,传递了当前表单初始值,angular完成校验工作后,又打开新增页面,这时就会报错.

网上有一些解决办法:

angular - ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'undefined' - Stack Overflowicon-default.png?t=N7T8https://stackoverflow.com/questions/45467881/expressionchangedafterithasbeencheckederror-expression-has-changed-after-it-was我的做法是,在编辑界面的取消函数中,重置表单信息.

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/382382
推荐阅读
相关标签
  

闽ICP备14008679号