【问题标题】:Diff between ViewEncapsulation.Native, ViewEncapsulation.None and ViewEncapsulation.EmulatedViewEncapsulation.Native、ViewEncapsulation.None 和 ViewEncapsulation.Emulated 之间的区别
【发布时间】:2016-06-09 16:26:12
【问题描述】:

谁能解释一下Angular2中的ViewEncapsulation.Native、 ViewEncapsulation.NoneViewEncapsulation.Emulated有什么区别强>。

我尝试用谷歌搜索并阅读了一些文章,但我无法理解其中的区别。

下面我有两个组件 Home (home.ts),即父组件和 MyComp (my-comp.ts)。我想在父组件中定义子组件中使用的样式。

我应该使用 ViewEncapsulation.Native 还是 ViewEncapsulation.None

home.ts

import {Component, ViewEncapsulation} from 'angular2/core';
import {MyComp} from './my-comp';
@Component({
  selector: 'home',  // <home></home>
  providers: [
  ],
  directives: [
    MyComp
  ],
  styles: [`
    .parent-comp-width {
       height: 300px;
       width: 300px;
       border: 1px solid black;
     }
    `],
  template:`
    <my-comp></my-comp>
    <div class="parent-comp-width"></div>
  `,
  encapsulation: ViewEncapsulation.Native
})
export class Home {
}

my-comp.ts

import {Component} from 'angular2/core';

@Component({
  selector: 'my-comp',  // <home></home>
  template: `
  <div class="parent-comp-width">my-comp</div>
  `
})
export class MyComp {
}

【问题讨论】:

  • 我的建议是始终使用ViewEncapsulation.None。至少在你知道你需要别人之前(;
  • 是的,如果您不关心视图封装,只需将其设置为 None 在任何地方,那么您就有了在 Web 组件前时代常见的行为。

标签: typescript angular


【解决方案1】:

更新 如果您希望将添加到Parent 的样式应用于Child,您需要在Child 组件中设置ViewEncapsulation.None,这样它就不会阻止样式渗入。

EmulatedNative 只是防止样式流入和流出组件的两种不同方法。 None 是唯一允许样式跨越组件边界的。

原创

  • ViewEncapsulation.None 简单无封装

  • ViewEncapsulation.Emulated(目前 Angular2 中的默认值)
    将属性添加到组件标签和子元素,并操作添加到页面的 CSS(将属性添加到选择器),这样样式就不会相互渗透 - 将样式保持在添加它们的组件的范围内,即使样式都是在加载组件时添加到页面头部的。

  • ViewEncapsulation.Native 使用影子 DOM 创建自定义元素,其中浏览器本机实现确保样式范围。
    如果浏览器本身不支持 shadow DOM,则需要 Web 组件 polyfill 来填充该行为。这类似于ViewEncapsulation.Emulated,但 polyfill 更昂贵,因为它们填充了大量的浏览器 API,即使它们中的大多数从未使用过。 Angulars Emulated 仿真只是增加了它使用的成本,因此对于 Angular 应用程序来说效率更高。

【讨论】:

  • None 是唯一允许样式跨越组件边界的样式 但在上面的代码中,子组件能够访问 parent-comp-width css 类。
  • @Gunter 你能详细说明 ViewEncapuslation.Native 因为我无法弄清楚,如果你能做到就太好了
  • @RahulSingh 抱歉,不知道要详细说明什么。它使用浏览器的影子 DOM 实现。现在使用它可能不是一个好主意,因为目前没有很好的样式和主题策略。
  • 根据我在下面的回答, ::ng-deep 是将父样式应用于子组件的另一种(即将弃用)方式。见stackoverflow.com/questions/36527605/…
  • @abyrne85 这与性能无关。我认为这不会产生显着影响。
【解决方案2】:

如果有人因为想通过父组件样式声明设置子组件样式而遇到这个问题,请参阅this SO answer

但是,正如对已接受答案的最新评论所示,Angular docs 说:

不推荐使用穿透阴影的后代组合器,支持 正在从主要浏览器和工具中删除。因此,我们计划放弃 Angular 中的支持(适用于所有 3 个 /deep/、>>> 和 ::ng-deep)。直到 那么 ::ng-deep 应该是首选,以获得更广泛的兼容性 工具。

【讨论】:

    【解决方案3】:
    • Native: 使用浏览器的原生 Shadow DOM。在启用之前检查浏览器支持。
    • ShadowDom: 使用浏览器的原生 Shadow DOM v1 以获得更好的跨浏览器支持,并且是跨浏览器的共享标准。检查 Shadow DOM v0 和 v1 之间的区别。
    • 模拟: 模仿 Shadow DOM 的行为来确定组件的 CSS 范围并附加到头部。
    • 无: 既不是 Shadow DOM,也不是自定义实现,比如附加到头部的全局 CSS

    Angular 使用 ViewEncapsulation.Emulated 作为默认封装模式。

    【讨论】:

    【解决方案4】:

    from pro-angular book:

    ViewEncapsulation 值:

    • Emulated:指定此值时,Angular 通过写入内容和样式以添加属性来模拟 Shadow DOM。如果未指定封装值,则这是默认行为。

      如果您使用浏览器的 F12 开发人员工具检查 DOM,您将看到外部 CSS 文件的内容。

        ...
        <style>
        div[_ngcontent-c0] {
          background-color: lightcoral;
        }
        </style>
        ...
    

    选择器已被修改,以匹配 div 元素 名为 _ngcontent-c0 的属性,尽管您可能会在 您的浏览器,因为属性的名称是由 Angular 动态生成的。

    为了确保样式元素中的 CSS 只影响组件管理的 HTML 元素,模板中的元素被修改为具有相同的动态生成属性,如下所示:

    ...
    <div _ngcontent-c0="" class="form-group">
       <label _ngcontent-c0="">Name</label>
       <input _ngcontent-c0="" class="form-control ng-untouched ng-pristineng-invalid" 
            ng-reflect-name="name" name="name">
    </div>
    ...
    
    • Native: 当指定这个值时,Angular 使用浏览器的 shadow DOM 特性。这只有在浏览器实现了 shadow DOM 或者您使用的是 polyfill 时才有效。
    • 无:当指定此值时,Angular 只是将未修改的 CSS 样式添加到 HTML 文档的 head 部分,并让浏览器弄清楚如何使用正常的 CSS 优先规则应用样式。李>

    应谨慎使用 Native 和 None 值。浏览器对 shadow DOM 功能的支持非常有限,只有当您使用为其他浏览器提供兼容性的 polyfill 库时,才可以使用 Native 选项。

    None 选项将组件定义的所有样式添加到 HTML 文档的 head 部分,并让浏览器确定如何应用它们。这样做的好处是可以在所有浏览器中工作,但是结果是不可预测的,并且不同组件定义的样式之间没有隔离。

    【讨论】:

      【解决方案5】:

      请参考以下示例以了解所有三个选项:

      encapsulation: ViewEncapsulation.Emulated
      encapsulation: ViewEncapsulation.Native
      encapsulation: ViewEncapsulation.None
      

      Click here看例子

      【讨论】:

        【解决方案6】:

        我们以ComponentParent 包含ComponentChild 的场景为例。对于此示例,我们正在讨论 ComponentParent 的不同封装场景。

        import { ViewEncapsulation }  from '@angular/core';
        
        @Component({
          selector: 'component-child',
          // templateUrl: './child.component.html',
          template: '<h1>Hello, child</h1>',
          // styleUrls: ['./child.component.scss'],
          style: '/* ... */'
        })
        export class ComponentParent {
          // ...
        }
        
        @Component({
          selector: 'component-parent',
          template: '<h1>Hello, parent</h1><component-child/>',
          style: 'h1{background-color:yellow}',
          encapsulation: ViewEncapsulation.Emulated // this is the default encapsulation for the angular component
        })
        export class ComponentParent {
          // ...
        }
        
        

        ViewEncapsulation 有 1 个废弃的值:

        和 3 个有效值:

        这是透明模式,最类似于完全不涉及角度的场景。

        ComponentParentComponentChild 都有黄色背景的 H1 标签。

        ShadowDom

        此模式在组件(在我们的例子中:ComponentParent)内容周围创建原生 shadow DOM 根。这将保护我们在组件内部声明的任何(CSS/SASS)样式泄漏到组件外部。但是,它将适用于 ComponentChild 等子组件。

        ComponentParentComponentChild 都会有黄色背景的 H1 标签(类似于None 模式),但ComponentParent 之外的任何 H1 标签都不会受到影响。

        模拟

        简而言之,这会将ComponentParent 中声明的样式仅应用于ComponentParent 内容,但排除子组件,如ComponentChild。换句话说,仅适用于“pure”HTML 元素,而不适用于 Angular Web(组件)元素。

        只有ComponentParent会有黄色背景的H1标签。

        Emulation机制补充说明

        Emulated 模式通常对我们来说是透明的,因为我们更喜欢将我们的全局样式(同时影响 ComponentParentComponentChild)放入将穿透 NoneEmulated 组件及其子组件和HTML 元素。

        但是,假设ComponentChild 是一个第 3 方组件,而您想要设置它的样式。在 ComponentParent 组件上应用 Emulated 模式时,您将无法做到这一点。这是由于Emulated 实现:

        ComponentParent 组件内的

        每个 HTML 元素将使用组件名称属性(无值)进行修饰,例如:

        • _nghost-c3:用于组件容器
        • _ngcontent-c3:用于组件的内容

        我们的组件ComponentParent中的并行每个(S)CSS选择器将被“封装”(条件)具有相同的组件名称属性

        .H1[_ngcontent-c3] {
          background-color:yellow;
        }
        

        总的来说,这意味着只有ComponentParent 的元素会受到影响,而我们装饰第 3 方组件的 H1 的目标将失败,因为它没有(相同的,如果有的话)组件名称属性(_ngcontent-c3)

        第 3 方组件的解决方案

        • 如果可用,请使用ShadowDom
        • 禁用封装,使用None
        • 将样式放入全局 (S)CSS
        • 通过使用组件名称属性装饰其元素来模拟内部第 3 方组件的模拟

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2021-12-25
          • 2020-05-10
          • 2014-09-20
          • 2010-10-28
          • 2015-10-04
          • 2012-08-12
          • 2011-02-18
          相关资源
          最近更新 更多