Angular如何進行視圖封裝?以下這篇文章給大家深入了解Angular Encapsulation的三種方式,希望對大家有幫助!
在日常工作中,當我們定義一個Component的時候,要考慮它的encapsulation封裝性,也就是說你期望這個元件裡定義的樣式是只作用於這個元件,還是想作用於全局。在 Angular 中,元件的樣式可以封裝在元件的宿主元素中,這樣它們就不會影響應用程式的其餘部分。 Component 的裝飾器提供了 encapsulation 選項,可用於控制如何基於每個元件套用視圖封裝。 【相關教學推薦:《angular教學》】
Angular中有三種封裝模式,分別是ViewEncapsulation.ShadowDom,ViewEncapsulation. Emulated,ViewEncapsulation.None。
export enum ViewEncapsulation { /** * Emulates a native Shadow DOM encapsulation behavior by adding a specific attribute to the * component's host element and applying the same attribute to all the CSS selectors provided * via {@link Component#styles styles} or {@link Component#styleUrls styleUrls}. * * This is the default option. */ Emulated = 0, /** * Doesn't provide any sort of CSS style encapsulation, meaning that all the styles provided * via {@link Component#styles styles} or {@link Component#styleUrls styleUrls} are applicable * to any HTML element of the application regardless of their host Component. */ None = 2, /** * Uses the browser's native Shadow DOM API to encapsulate CSS styles, meaning that it creates * a ShadowRoot for the component's host element which is then used to encapsulate * all the Component's styling. */ ShadowDom = 3 }
如果沒有提供,該值就會從 CompilerOptions 中取得它。預設的編譯器選項是 ViewEncapsulation.Emulated。
如果該策略設定為 ViewEncapsulation.Emulated,且元件沒有指定 styles 或 styleUrls,就會自動切換到 ViewEncapsulation.None。
有沒有發現枚舉型別了為什麼沒有1?這個待會再說。
拋開Angular中的ShadowDom的封裝,先來看看什麼是ShadowDOM。
Shadow DOM 允許將隱藏的DOM 樹附加到常規的DOM 樹中——它以shadow root 節點為起始根節點,在這個根節點的下方,可以是任意元素,和普通的DOM 元素一樣。
這裡,有一些Shadow DOM 特有的術語需要我們了解:
你可以用相同的方式來操作Shadow DOM,就和操作常規DOM 一樣-例如新增子節點、設定屬性,以及為節點新增自己的樣式(例如透過element.style 屬性),或為整個Shadow DOM 新增樣式(例如在 元素內新增樣式)。不同的是,Shadow DOM 內部的元素始終不會影響到它外部的元素(除了 :focus-within),這為封裝提供了便利。
我們來看一個簡單的例子吧。
nbsp;html> <meta> <meta> <meta> <title>Shadow DOM</title> <style> span{ color: green; } </style> <span>我是Root</span> <div></div> <script> let app = document.querySelector('#app'); let shadow1 = app.attachShadow({ mode: 'open'}); let style1 = document.createElement('style'); style1.appendChild(document.createTextNode("span{color: red;}")); shadow1.appendChild(style1); let span1 = document.createElement('span'); span1.textContent = 'I am span.'; shadow1.appendChild(span1); </script>
上面的例子,定義了全局span的樣式,也定義了shadowDOM裡的span樣式,可以看出互相不受影響。
了解了什麼是ShadowDOM後,再來看Angular中ShadowDOM的封裝。
Angular 使用浏览器内置的 Shadow DOM API 将组件的视图包含在 ShadowRoot(用作组件的宿主元素)中,并以隔离的方式应用所提供的样式。ViewEncapsulation.ShadowDom 仅适用于内置支持 shadow DOM 的浏览器。并非所有浏览器都支持它,这就是为什么 ViewEncapsulation.Emulated 是推荐和默认模式的原因。
比如下面的这个例子,使用ViewEncapsulation.ShadowDom。
@Component({ selector: 'user-child', templateUrl: 'UserChild.component.html', styles: [` h3{ color: red; } `], encapsulation: ViewEncapsulation.ShadowDom }) export class UserChildComponent implements OnInit { ...... }
从运行的页面上看到,user-child组件内部被封装成了一个ShadowDOM,style也被封装在了里面,并不会对外部的样式造成影响。
Angular 会修改组件的 CSS 选择器,使它们只应用于组件的视图,不影响应用程序中的其他元素(模拟 Shadow DOM 行为)。
使用模拟视图封装时,Angular 会预处理所有组件的样式,以便它们仅应用于组件的视图。在正运行的 Angular 应用程序的 DOM 中,使用模拟视图封装模式的组件所在的元素附加了一些额外的属性:
<hero-details> <h3>Mister Fantastic</h3> <hero-team> <h4>Team</h4> </hero-team> </hero-details>
有两种这样的属性:
属性 | 详情 |
---|---|
_nghost | 被添加到包裹组件视图的元素中,这将是本机 Shadow DOM 封装中的 ShadowRoots。组件的宿主元素通常就是这种情况。 |
_ngcontent | 被添加到组件视图中的子元素上,这些属性用于将元素与其各自模拟的 ShadowRoots(具有匹配 _nghost 属性的宿主元素)相匹配。 |
这些属性的确切值是 Angular 的私有实现细节。它们是自动生成的,你不应在应用程序代码中引用它们。
它们以生成的组件样式为目标,这些样式会被注入到 DOM 的 部分:
[_nghost-pmm-5] { display: block; border: 1px solid black; } h4[_ngcontent-pmm-6] { background-color: white; border: 1px solid #777; }
这些样式经过后期处理,以便每个 CSS 选择器都使用适当的 _nghost 或 _ngcontent 属性进行扩充。这些修改后的选择器可以确保样式以隔离和有针对性的方式应用于组件的视图。
<p>child works!</p>
p{ color: green; }
@Component({ selector: 'app-child', templateUrl: './child.component.html', styleUrls: ['./child.component.scss'], encapsulation: ViewEncapsulation.Emulated }) export class ChildComponent implements OnInit { ...... }
ViewEncapsulation.Emulated 设置的结果是没有 Shadow DOM,但是通过 Angular 提供的样式包装机制来封装组件,使得组件的样式不受外部影响。虽然样式仍然是应用到整个 document,但 Angular 为 p创建了一个 [_ngcontent-oow-c11] 选择器。可以看出,我们为组件定义的样式,被 Angular 修改了。简单来说,尽管是也是全局样式,但是由于自动选择器的原因,并不会影响其他组件的样式。如果手动在其他元素上也添加这个属性,则样式也会应用到这元素上。
Angular 不应用任何形式的视图封装,这意味着为组件指定的任何样式实际上都是全局应用的,并且可以影响应用程序中存在的任何 HTML 元素。这种模式本质上与将样式包含在 HTML 本身中是一样的。
parent:
<p>parent works!{{count}}</p> <p>第一个:{{count}}</p> <span>parent</span> <app-child></app-child>
child:
<p>child works!</p> Child
p{ color: green; } .red-font { color: red; }
@Component({ selector: 'app-child', templateUrl: './child.component.html', styleUrls: ['./child.component.scss'], encapsulation: ViewEncapsulation.None }) export class ChildComponent implements OnInit { ...... }
在Angular2中使用ViewEncapsulation.Native。
@Component({ ..., encapsulation: ViewEncapsulation.Native }) export class UserComponent {
ViewEncapsulation.Native 设置的结果是使用原生的 Shadow DOM 特性。Angular 会把组件按照浏览器支持的 Shadow DOM 形式渲染。其实这种就是后来的ViewEncapsulation.ShadowDom。
我们介绍了Angular视图封装的三种方式,各自的特点,日常工作中要根据特定的场景去选择哪种封装方式。
更多编程相关知识,请访问:编程视频!!
以上是Angular如何進行視圖封裝?聊聊三種封裝模式的詳細內容。更多資訊請關注PHP中文網其他相關文章!