【问题标题】:How to solve View Encapsulation issue in Angular8?如何解决 Angular 8 中的视图封装问题?
【发布时间】:2020-03-10 21:45:20
【问题描述】:

我有父组件和子组件。作为模态组件创建的子组件。所以我在父组件中包含了子组件选择器,并且我设置了视图封装是无的,因此它将采用父组件css和所有它也可以工作,但是父组件有#paper id应用了一些第三方(rappidjs)库css(对于SVG 图表)。像子组件一样具有#dataMapper id。但这里第三方 css 没有采用,因为子组件设置为 'encapsulation: ViewEncapsulation.None'。如果我将删除 encapsulation: ViewEncapsulation.None 它正在工作,但模式不起作用。所有模态加载而不是onclick。如何解决这个问题,请给我建议。

编码:

父组件 TS

@Component({
  selector: 'app-data-model',
  templateUrl: './data-model.component.html',
  styleUrls: ['./data-model.component.css']
})

export class DataModelComponent implements OnInit{

// Modal

openModal(id: string) {
  this.modalApp = true;
  this.modalService.open(id);
}

closeModal(id: string) {
  this.modalService.close(id);
}

父组件 HTML

<div id="toolbar">
    <div class="tool-bar-section">
    <button class="btn" (click)="openModal('custom-modal-1');"><i class="fa fa-file-excel-o" style="font-size: 24px"></i></button>     
    </div>   
</div>
<div id="paper"> </div> ( this dom taking thirdparty css)

<app-modal id="custom-modal-1">           
    <h1 class="head-bar">Data Model - Import Excel  <a href="#" class="close-icon" (click)="closeModal('custom-modal-1');"><i class="fa fa-times-circle-o" aria-hidden="true"></i></a></h1>
    <div class="modal-content-section">
     <ul>
         <li><a href="#" (click)="closeModal('custom-modal-1');openModal('custom-modal-2');">Create New Schema</a></li>
         <li><a href="#" (click)="closeModal('custom-modal-1');openModal('custom-modal-3');">Import Data to existing schema</a></li>
     </ul>       
    </div>        
</app-modal>
<app-modal id="custom-modal-2">       
    <h1 class="head-bar">Data Model - Import Excel  <a href="#" class="close-icon" (click)="closeModal('custom-modal-2');"><i class="fa fa-times-circle-o" aria-hidden="true"></i></a></h1>
    <div class="modal-content-section">
        <div id="dataMapper"></div>       ( this dom is not taking thirdparty css)
        <p><a href="#" (click)="closeModal('custom-modal-2');openModal('custom-modal-4');">Data Mapping</a></p>
    </div>
</app-modal>

子组件 HTML

<div class="app-modal">
    <div class="app-modal-body">
        <ng-content></ng-content>
    </div>
</div>
<div class="app-modal-background"></div>

子组件 Ts

@Component({
  selector: 'app-modal',
  templateUrl: './modal.component.html',
  styleUrls: ['./modal.component.css'],
  encapsulation: ViewEncapsulation.None
})
export class ModalComponent implements OnInit, OnDestroy {

  @Input() id: string;
  private element: any;

  constructor(private modalService: ModalService, private el: ElementRef) {
      this.element = el.nativeElement;
  }

  ngOnInit(): void {
      // ensure id attribute exists
      if (!this.id) {
          console.error('modal must have an id');
          return;
      }

      // move element to bottom of page (just before </body>) so it can be displayed above everything else
      document.body.appendChild(this.element);

      // close modal on background click
      this.element.addEventListener('click', el => {
          if (el.target.className === 'app-modal') {
              this.close();
          }
      });

      // add self (this modal instance) to the modal service so it's accessible from controllers
      this.modalService.add(this);
  }

  // remove self from modal service when component is destroyed
  ngOnDestroy(): void {
      this.modalService.remove(this.id);
      this.element.remove();
  }

  // open modal
  open(): void {
      this.element.style.display = 'block';
      document.body.classList.add('app-modal-open');
  }

  // close modal
  close(): void {
      this.element.style.display = 'none';
      document.body.classList.remove('app-modal-open');
  }

}

模式服务代码

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class ModalService {

  private modals: any[] = [];

  add(modal: any) {
      // add modal to array of active modals
      this.modals.push(modal);
  }

  remove(id: string) {
      // remove modal from array of active modals
      this.modals = this.modals.filter(x => x.id !== id);
  }

  open(id: string) {
      // open modal specified by id
      const modal = this.modals.find(x => x.id === id);
      modal.open();
  }

  close(id: string) {
      // close modal specified by id
      const modal = this.modals.find(x => x.id === id);
      modal.close();
  }
}

如果需要更多详细信息,请告诉我。

【问题讨论】:

  • 尝试添加一个 stackblitz 示例而不是发布一堆代码。
  • @AkhilAravind - 添加 stackblitiz 可能需要更多时间。因为它是大型应用程序,我只将代码放在问题所在。
  • 我们不需要完整的代码块,只需要一个最小的示例来重现问题。
  • 你能发布一些应该应用的css和选择器的例子吗?目前还不清楚这里出了什么问题。如果这个第三方 css 是基于 id 的,那么如果这些 ID 在页面上出现多次,就像这些组件在任何地方被重用一样,那将是非常有问题的。只有 id 的第一个实例会采用样式
  • 如果您可以在 stackblitz 中创建一个最小的可重现问题,这将有助于我们所有人解决您的问题。不要包括您的整个项目,只包括您遇到此问题的部分。

标签: javascript angular


【解决方案1】:

因为你的模态。 modal 是在您的应用的 top 上创建的,(如果您通过检查来查找 modal wrapper,则它是 out of body 标记。)

是Modal导致dom结构与ng组件结构不同步

那么为什么模态与 ng Encapsulation 一起使用?因为您的模态服务可以处理它。

但第 3 方 CSS 文件不是您的角度编译配置的一部分(即只有 sass、scss 有效)。因此,即使您正确导入它,它也会忽略任何 .css

要解决它,您可以全局应用 .css。或者如果你害怕可能覆盖其他全局样式,你可以将css文件重命名为'_somefile.scss'(注意破折号'_',这很重要。)

然后在你的项目全局 style.scss 文件下 > 创建一个匹配你的模态包装器的选择器 > 在选择器下:添加一行 @import somefile (不要添加扩展名)

style.scss

.modal-wrapper {
    @import somepath/somefile
}

【讨论】:

    【解决方案2】:

    正如您在问题中所描述的,您希望在子组件中继承父组件的 css。因此,我假设您在父组件和子组件中具有相同的 HTML 元素,并且您不想复制您的 css。

    由于我们无法复制您的问题,并且您还没有创建任何 stackblitz 实例。我会建议一个更好的替代方案。请在下面找到它:

    我们可以在@Component 装饰器元数据对象的styleUrls 属性中指定多个CSS URL。所以,我建议你也传递父样式文件 Url。

    我创建了一个基本的堆栈闪电战,显示我在哪里访问父组件的 CSS:https://stackblitz.com/edit/angular-jhewzy

    父组件css文件(app.component.css) - 我指定父级内p 标记的背景颜色应为黄色。我想在子组件中继承它。

    p {
      background-color: yellow;
    }
    

    下面是子组件 CSS (hello.component.css)

    p {
      font-style: italic;
    }
    

    如果您想在子组件中使用父组件,只需使用 styleUrls 属性中的样式 URL 路径

    import { Component, Input } from '@angular/core';
    
    @Component({
      selector: 'hello',
      template: `<p>I am child</p>`,
      styleUrls: [`./hello.component.css`, './app.component.css'],
    })
    
    
    export class HelloComponent  {
      @Input() name: string;
    }
    

    希望对你有帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-20
      • 2020-01-16
      • 2016-11-10
      • 1970-01-01
      • 2019-11-28
      • 2021-09-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多