shadow DOM

什么是shadow DOM?

将一组隐藏的、独立的DOM结构附加到某个元素上。比如在video元素的shadow DOM上,就隐藏了许多对视频控制的按钮和控制器等。

shadow host:一个常规的DOM节点,shadow DOM 会被附加到这个节点上

shadow tree:shadow DOM 内部的DOM tree

shadow root:shadow tree的根节点

shadow boundary:shadow tree结束的地方,也就是常规DOM开始的地方

和操作常规DOM一样,可以用相同的方式操作Shadow DOM ,比如为其添加子节点,设置属性、样式等。不同的是,shadow DOM 始终不会影响其外部的元素,

除了:focus-within(是一个css伪类,表示一个元素获得焦点,或该元素的后代获得焦点)

基本用法

Element.attachShadow() :

将一个shadow root添加到某个元素上,接收一个对象作为参数:{mode: ‘open/closed‘}。当为open时允许以js的方式操作shadow DOM,closed时不允许外部对其进行操作

如果想将一个shadow DOM 附加到常规DOM上,就可以在常规DOM的构造函数中:

let  shadow = this.attachShadow({mode: ‘open‘});

之后就可以通过js对其进行操作,如下

let img = document.createElement(‘img‘);
shadow.appendChild(img);

以下为MDN中的示例:shadow dom包含一个图片icon和一个隐藏的info,当图片icon获得焦点时info显示,内容为说明信息

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body><!--在页面中直接使用 -->
    <popup-info img="C:\Users\asus\Pictures\Saved Pictures" text="Your card validation code (CVC) is an extra security feature — it is the last 3 or 4 numbers on the back of your card.">
</body>
<script>  // 创建一个常规DOM,用来添加shadow dom
    class popUpInfo extends HTMLElement{
        constructor(){
            super();        // 创建一个shadow root
            var shadow = this.attachShadow({mode: ‘open‘});                // 创建三个span。并未它们赋予class属性和值
            var wrapper = document.createElement(‘span‘);
            wrapper.setAttribute(‘class‘, ‘wrapper‘);
            var icon = document.createElement(‘span‘);
            icon.setAttribute(‘class‘, ‘icon‘);
            icon.setAttribute(‘tabindex‘, 0);
            var info = document.createElement(‘span‘);
            info.setAttribute(‘class‘, ‘info‘);        // 将当前元素上的text属性值赋值给info的内容,info就是用来显示图片的说明信息
            var text = this.getAttribute(‘text‘);
            info.textContent = text;
      // 将当前元素的img属性值获取,创建一个img元素,放到icon中
            var imgUrl;
            if (this.hasAttribute(‘img‘)) {
                imgUrl = this.getAttribute(‘img‘);
            }else{
                imgUrl = ‘img/default.png‘;
            }
            var img = document.createElement(‘img‘);
            img.src = imgUrl;
            icon.appendChild(img);// 为 shadow DOM 添加一些 CSS 样式
        var style = document.createElement(‘style‘);
        style.textContent = 
        `.wrapper {
            position: relative;
        }

        .info {
            font-size: 0.8rem;
            width: 200px;
            display: inline-block;
            border: 1px solid black;
            padding: 10px;
            background: white;
            border-radius: 10px;
            opacity: 0;
            transition: 0.6s all;
            position: absolute;
            bottom: 20px;
            left: 10px;
            z-index: 3;
        }
        img {
            width: 1.2rem;
        }
        .icon:hover + .info, .icon:focus + .info {
            opacity: 1;
        }`;     // 将样式和wrapper添加给shadow
        shadow.appendChild(style);
        shadow.appendChild(wrapper);      // wrapper中包含icon和info
        wrapper.appendChild(icon);
        wrapper.appendChild(info);
    }
}

  // 定义常规DOM  
customElements.define(‘popup-info‘, popUpInfo);

</script>
</html>