Shadow DOM

JavaScript Shadow DOM (JavaScript阴影DOM)

In this chapter, we are going to cover the main means of encapsulation: Shadow DOM. With it, a component can have its “shadow” DOM tree, which may be accidentally accessed from the core document, can obtain local style rules, and so on.

Built-in Shadow DOM

Built-in Shadow DOM (内置Shadow DOM)

The browser applies DOM/CSS for creating complex browser controls. The DOM structure may be concealed, but it can be seen in the developer tools. For example, in Chrome, it is necessary to enable the “Show user agent shadow DOM” option in Dev tools. Regular JavaScript calls or selectors can’t bring built-in shadow DOM elements. A useful attribute pseudo, in the example above, is non-standard one. It can be used in style sublements with CSS, in the following way:

<!DOCTYPE html>
<html>
 <head>
   <title>Title of the document</title>
   <style>
     /* make the slider track green */
(/*使滑块轨道变绿*/)
     input::-webkit-slider-runnable-track {
       background: green;
     }
   </style>
 </head>
 <body> 
   <input type="range">
 </body>
</html>

Shadow Tree

Shadow Tree (影子树)

Any DOM element contains two types of DOM subtrees: Light Tree and Shadow tree. The first one is a regular DOM subtree, based on HTML children. All the subtrees, we have covered in the previous chapters, were of this type. The shadow tree is a concealed subtree that is not reflected in HTML. In case an element includes both of the subtrees, then the browser will render only the shadow tree.

Setting up a composition between light and shadow trees is also possible. You can use the shadow tree in Custom elements for hiding component internals and applying component-local styles. (也可以在光树和阴影树之间设置构图。 您可以使用自定义元素中的阴影树来隐藏组件内部并应用组件本地样式。)

Here is an example:

<!DOCTYPE html>
<html>
 <head>
   <title>Title of the document</title>
 </head>
 <body>
   <show-welcome name="w3cdoc"></show-welcome>
 </body>
 <script>
   customElements.define('show-welcome', class extends HTMLElement {
     connectedCallback() {
       const shadow = this.attachShadow({mode: 'open'});
       shadow.innerHTML = `<h1>
         Welcome to ${this.getAttribute('name')}
       </h1>`;
     }
   });
 </script> 
 </body>
</html>

So, the first elem.attachShadow({mode: …}) call makes a shadow tree.

But, two limitations can turn up:

Only one shadow root can be created per element. The elem should be either a custom element or one of the following: “article”, “aside”, “blockquote”, “body”, “div”, “footer”, “h1…h6”, “header”, “main” “nav”, “p”, “section”, or “span”. Take into consideration that the shadow tree can’t include elements like <img>.

The encapsulation level is set up by the mode option, which has the following values:

“open”: the shadow root is represented as elem.shadowRoot. The shadow tree of elem can be accessed by any code. “closed”:elem.shadowRoot is permanently null.

So, the shadow Dom can only be accessed by the reference returned by attachShadow. The browser-native shadow trees like <input type=“range”> are close, giving no way of accessing them.

Also, there exists an element with shadow root, known as “shadow tree host”. It is available as the shadow root host property, like this:

<!DOCTYPE html>
<html>
 <head>
   <title>Title of the document</title>
   <style>
     /* the document style will not apply to the shadow tree inside #elem*/
     h1 { color: red; }
   </style>
 </head>
 <body>
   <div id="elem"></div>
   <script>
     elem.attachShadow({mode: 'open'});
       // shadow tree has its own style 
(//阴影树有自己的风格)
     elem.shadowRoot.innerHTML = `
       <style> h1 { font-weight: bold; } </style>
       <h1>Welcome to w3cdoc</h1>
     `;
     //need {mode: "open"}, otherwise elem.shadowRoot is null
     alert(elem.shadowRoot.host === elem); // true     
   </script>
 </body>
</html>

Encapsulation

Encapsulation (封装)

There is a strong delimitation between the shadow DOM and the main document:

From the light DOM, shadow DOM elements are not visible to querySelector. Particularly, Shadow DOM elements can have ids conflicting with the elements in the light DOM. Shadow DOM obtains own stylesheets. The style rules from the outer DOM will not be applied. Here is how it looks like:

<!DOCTYPE html>
<html>
 <head>
   <title>Title of the document</title>
   <style>
     /* the document style will not apply to the shadow tree inside #elem */
     h1 { color: green; }
   </style>
 </head>
 <body>
   <div id="elem"></div>
   <script>
     elem.attachShadow({mode: 'open'});
       // shadow tree has its own style 
(//阴影树有自己的风格)
     elem.shadowRoot.innerHTML = `
       <style> h1 { font-weight: bold; } </style>
       <h1>Welcome to w3cdoc</h1>
     `;      
     // <h1> is only visible from queries inside the shadow tree 
     alert(document.querySelectorAll('h1').length); // 0
     alert(elem.shadowRoot.querySelectorAll('h1').length); // 1
   </script>
 </body>
</html>

So, the style from the document will not impact the shadow tree. However, the style coming from inside will do. (因此,文档中的样式不会影响阴影树。但是,来自内部的风格可以。)

For getting the shadow tree elements, it is required to query from inside the tree. (要获取阴影树元素,需要从树内部查询。)

Summary

Summary (概要)

In this chapter, we covered the shadow DOM, which is a way of creating a component-local DOM. (在本章中,我们介绍了阴影DOM ,这是一种创建组件本地DOM的方法。)

You can use shadowRoot = elem.attachShadow({mode: open|closed}) for creating shadow DOM for elem. Once there is mode=“open”, you can access it as elem.shadowRoot property. The shadowRoot can be populated with innerHTML and other methods of DOM.

The elements of shadow DOM:

  • contain own ids space. (-包含自己的ID空间。)

  • they are not visible to JavaScript selectors from the core document like querySelector. (-它们对核心文档(如querySelector )中的JavaScript选择器不可见。)

  • only the styles inside the shadow tree are used by them. (-他们只使用阴影树中的样式。)

You will get more information about the shadow DOM in chapter Shadow DOM Slots, Composition. (您将在“Shadow DOM Slots, Composition”一章中获得有关阴影DOM的更多信息。)



请遵守《互联网环境法规》文明发言,欢迎讨论问题
扫码反馈

扫一扫,反馈当前页面

咨询反馈
扫码关注
返回顶部