首页 > 建站教程 > JS、jQ、TS >  shadow dom的作用和用法详解(createShadowRoot, attachShadow)正文

shadow dom的作用和用法详解(createShadowRoot, attachShadow)

相信shadow dom很多前端开发工作者都遇到过(点击查看HTML5 audio、video原生样式修改,查看shadow dom的方法),它是web component的一部分。不过对于shadow dom很多人并不深入了解,只晓得是影子dom结构,那么到底什么是shadow dom的,本文将从概念,作用,用法三个方面来介绍下shadow dom.

介绍shadow dom之前,首先看几个常用的标签,例子1:
<video controls autoplay name="media">
    <source id="mp4" src="http://media.w3.org/2010/05/sintel/trailer.mp4" type="video/mp4">
</video>
 
<-- 实际显示 -->
<video src="a.mp4" width="480" height="360">
    #shadow root
    <div pseudo="-webkit-media-controls">
        <div pseudo="-webkit-media-controls-overlay-enclosure">
            <input type="button" style="display: none;">
        </div>
        <div pseudo="-webkit-media-controls-enclosure">
            <div pseudo="-webkit-media-controls-panel" style="display: none;">
                <input type="button" pseudo="-webkit-media-controls-play-button">
                <input type="range" step="any" pseudo="-webkit-media-controls-timeline" max="0">
                <div pseudo="-webkit-media-controls-current-time-display" style="display: none;">0:00</div>
                <div pseudo="-webkit-media-controls-time-remaining-display">0:00</div>
                <input type="button" pseudo="-webkit-media-controls-mute-button">
                <input type="range" step="any" max="1" pseudo="-webkit-media-controls-volume-slider" style="display: none;">
                <input type="button" pseudo="-webkit-media-controls-toggle-closed-captions-button" style="display: none;">
                <input type="button" style="display: none;">
                <input type="button" pseudo="-webkit-media-controls-fullscreen-button" style="display: none;">
            </div>
        </div>
    </div>
</video>
video标签就是shadow dom结果,从上述代码可以看出,在渲染之后,显示了很多内部封装的结构。

<input type="range">,<audio></audio>也是shadow dom结构。

shadow概念:
    Shadow DOM 是一个 HTML 的规范,其允许开发者封装自己的 HTML 标签、CSS 样式和 JavaScript代码。

shadow功能:
    既然是封装html片段,那么功能显而易见,就是让开发人员可以创建出诸如 video这样自定义的一级标签,并且Shadow-dom 具有良好的密封性,方便复用。

Shadow-dom 是游离在 DOM 树之外的节点树,Shadow-dom 具有良好的密封性

shadow-dom Api详解
先来一段html, 以下操作基于该html
<body>
    <div id="notificaton">
        <p>createShadowRoot</p>
       <button>学习</button>
    </div>
    <div id="notificatonNew">
        <p>attachShadow</p>
        <button>学习</button>
        <span slot="main1" class = "slot-test">
            插槽1
        </span>
        <span slot="main2">
            插槽2
        </span>
        <template id="tpl">
            <style>
                span {
                color:red;
                }
            </style>
            <!-- 这里将显示影子根节点中定义的插槽内容 -->
            <slot name="main1"></slot>
            <slot name="main2"></slot>
            <span>hello world</span>
        </template>
    </div>
</body>
1、老api createShadowRoot
//创建shadow后,notificaton元素及子节点内容不可见
const shadow = document.getElementById('notificaton').createShadowRoot();
2、新的api attachShadow
const notificatonNew = document.getElementById('notificatonNew');
const shadowroot = notificatonNew.attachShadow({mode:'open'});
说明:attachShadow参数含义

    mode: 一个指定Shadow DOM封装模式的字符串,可以是下列之一:
        open指定为开放的封装模式。
        closed指定为关闭的封装模式。

给影子dom添加内容:

    通过innerHTML添加:
shadow.innerHTML = `
        <style>:host {
            font-weight: bold;
            color:blue;
        }</style>
        <p class = "shadow-inside-node">Lorem ipsum dolor sit amet.</p>
        <content select="span">
          Lorem ipsum dolor sit amet.
          <div>test-div</div>
        </content>
        `
说明://:host伪选择器,通过:host可以选择shadow

    通过模板添加:
//'tpl'是上面template的id
shadowroot.appendChild(document.getElementById('tpl').content.cloneNode(true));
    扩展功能:插槽slot的使用

shadow中可以使用插槽,在要创建shadow dom的元素内先定义好插槽,然后在模板中使用插槽,渲染时会替换插槽。
shadowroot.innerHTML = `
     <style>
         :host { color: blue; }
     </style>
         <slot name="main1"></slot>
         <slot name="main2"></slot>
         <slot>
     `
在模板中使用
<div id="notificatonNew">
        <p>attachShadow</p>
        <button>学习</button>
        <span slot="main1" class = "slot-test">
            插槽1
        </span>
        <span slot="main2">
            插槽2
        </span>
        <template id="tpl">
            <style>
                span {
                color:red;
                }
            </style>
            <!-- 这里将显示影子根节点中定义的插槽内容 -->
            <slot name="main1"></slot>
            <slot name="main2"></slot>
            <span>hello world</span>
        </template>
</div>
slot属于较新的api,存在兼容性问题,尽量不要在生产环境使用

参考:https://www.imweb.io/topic/5593cc62799539f821cd2541
https://blog.csdn.net/Aijn_faluts/article/details/88658884
https://www.cnblogs.com/yangguoe/p/8486046.html
https://www.jianshu.com/p/9293cac60920
https://developer.mozilla.org/zh-CN/docs/Web/API/Element/attachShadow