Try   HackMD

View Encapsulation

Angular cung cấp tính năng View Encapsulation với mục đích đóng gói và làm tăng khả năng tái sử dụng của các components.

Shadow DOM

Đây là một API của HTML, cho phép tạo ra các phần tử độc lập trên trang web. Chúng không thể bị can thiệp bởi stylesheet hay JS từ bên ngoài và ngược lại. Ví dụ thẻ <video>, <iframe>là một trong những shadow DOM.

Một shadow DOM sẽ bao gồm các thành phần:

  • Shadow host: Là một phần tử DOM thông thường, nơi mà shadow DOM được gắn vào.
  • Shadow tree: Bao gồm toàn bộ nội dung HTML (DOM tree) của shadow DOM.
  • Shadow boundary: Giới hạn phạm vi của một shadow DOM.
  • Shadow root: Là root note của toàn bộ shadow tree.

Create shadow DOM

Để tạo một shadow DOM chúng ta có thể sử dụng phương thức attachShadow được hỗ trợ trong HTML5.

  • Định nghĩa template cho element:
<template id="my-element">
  <style>
    .inner {
      color: red;
    }
  </style>
  <div class="inner">
    This content is inside the shadow DOM
  </div>
</template>
  • Tạo và attach shadow DOM:
<script>
  class MyElement extends HTMLElement {
    constructor() {
      super();
      const shadowRoot = this.attachShadow({mode: 'open'});
      const template = document.getElementById('my-element');
      shadowRoot.appendChild(template.content.cloneNode(true));
    }
  }

  customElements.define('my-element', MyElement);
</script>

Ở đây, chúng ta tạo một custom element , shadow DOM sẽ được attach trực tiếp lên element đó. Chúng ta cũng có thể attach shadow DOM lên một element bất kỳ thông qua phương thức attachShadow của nó:

<script>
  const shadowHost = document.querySelector('#shadow-host');
  const shadowRoot = shadowHost.attachShadow({mode: 'open'});
  shadowRoot.innerHTML = '<span>Inside shadow DOM</span>';
</script>

Using shadow DOM

Tương tự như các thẻ cơ bản khác của HTML, để sử dụng shadow DOM chúng ta chỉ cần gọi:

<my-element></my-element>

Trình duyệt sau đó sẽ render ra nội dung tương ứng:

<my-element>
  #shadow-root
    <style>
      .inner {
        color: red;
      }
    </style>
    <div class="inner">
      This is inside the shadow DOM
    </div>
</my-element>

Shadow host trong trường hợp này là <my-element></my-element>, mỗi một phần tử sẽ có một shadowRoot, toàn bộ nội dụng HTML trong template sẽ được quản lý bởi shadow root này.

Nội dung của thẻ div.inner sẽ không bị tác động bởi stylesheet hay JS bên ngoài, nó chỉ chịu sự tác động bởi các thay đổi diễn ra bên trong <my-element>.

Qua ví dụ trên, chúng ta cũng phần nào hiểu được cơ chế attach directive trong Angularjs. Với các restrict: A, E, C, M, Angularjs sẽ xác định một directive sẽ được attach lên những phần tử nào trên trang web.

Angular View Encapsulation

Trong Angular, chúng ta có thể đóng gói một component thông qua view encapsulation modes:

  • ViewEncapsulation.ShadowDom: Angular sử dụng Shadow DOM API như đã nói ở trên. Đây là mức độ đóng gói cao nhất của component.

  • ViewEncapsulation.Emulated: Với mode này, Angular sẽ add thêm attribute vào tất cả các element thuộc DOM tree của component:

    ​​​​<hero-details _nghost-pmm-5>
    ​​​​  <h2 _ngcontent-pmm-5>Mister Fantastic</h2>
    ​​​​  <hero-team _ngcontent-pmm-5 _nghost-pmm-6>
    ​​​​    <h3 _ngcontent-pmm-6>Team</h3>
    ​​​​  </hero-team>
    ​​​​</hero-details>
    

    Từ đó đảm bảo việc apply stylesheet sẽ chỉ có tác động trong phạm vi của component:

    ​​​​[_nghost-pmm-5] {
    ​​​​  display: block;
    ​​​​  border: 1px solid black;
    ​​​​}
    ​​​​h3[_ngcontent-pmm-6] {
    ​​​​  background-color: white;
    ​​​​  border: 1px solid #777;
    ​​​​}
    

    Tuy nhiên, các phần tử trong component vẫn có thể bị tác động bởi các script JS bên ngoài.

  • ViewEncapsulation.None: Component sẽ không được đóng gói, nghĩa là nó sẽ bị tác động bởi các stylesheet và JS bên ngoài. Ngược lại, stylesheet và JS bên trong component cũng có thể ảnh hưởng đến bất kỳ phần tử nào trên trang web.

Mixing encapsulation modes

Khi có nhiều component lồng nhau, mỗi component lại có encapsulation mode khác nhau thì chúng sẽ hoạt động như thế nào? Hiểu đơn giản, encapsulation mode cũng có scope tương tự như variable scope trong JS.

Theo đó block scope, function scopeglobal scope sẽ tương ứng với 3 mode ShadowDom, EmulatedNone ở trên. Từ đây có thể biết được, các mode sẽ có tác động lên nhau như thế nào trong từng trường hợp.