Web Components详解-Shadow DOM插槽

简介: Web Components详解-Shadow DOM插槽

前言

插槽实际上也属于组件通信的一种方式,但是由于其强大的api和实用性,我将其单独拆开来介绍。

定义

Slot(插槽)是Web Components中一个重要的特性,它允许在组件内部定义占位符,以便父组件可以向其中插入内容。换句话说就是将子组件或者标签传入父组件中,最终达到在父组件外部实现子组件的效果

基本用法

slot属于Shadow DOM的一部分,在原生html中并不支持插槽的写法,所以我们必须将标签放在Shadow DOM中。

插槽标签的写法

<slot name="标签slot属性值"></slot>

需要传入的标签必须在对应的自定义标签中定义

<my-custom-element>
    <div slot="标签slot属性值">标签</div>
</my-custom-element>

完整示例参考下面的代码

<!DOCTYPE html>
<html lang="en">
 
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ShadowDOM</title>
</head>
 
<body>
    <my-custom-element>
        <header slot="header">header</header>
        <main slot="content">
            <span>content</span>
        </main>
        <footer slot="footer">footer</footer>
    </my-custom-element>
    <div id="slots">
        <slot name="header"></slot>
        <slot name="content"></slot>
        <slot name="footer"></slot>
    </div>
 
    <script>
        const elemName = "my-custom-element"
        const ele = document.querySelector(elemName)
        const slots = document.querySelector("#slots")
        class MyCustomElement extends HTMLElement {
            constructor() {
                super()
                this.attachShadow({ mode: 'open' });
                this.shadowRoot.appendChild(slots)// 插槽必须在shadowDOM中
            }
        }
        customElements.define(elemName, MyCustomElement)
    </script>
</body>
 
</html>

具名插槽

具名插槽实际上就是上面的用法,在自定义标签中使用<div slot="标签slot属性值">标签</div>以及在影子DOM中使用<slot name="标签slot属性值"></slot>的形式达到效果

DOM的结构如下

匿名插槽

匿名插槽又叫默认插槽,当有slot标签不设置name属性,并且在自定义标签中存在未设置slot属性的其他标签,即具名插槽的name属性以及slot属性均未设置,此时第一个slot标签就会承载自定义标签中的全部匿名标签,参考下面的代码

<!DOCTYPE html>
<html lang="en">
 
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ShadowDOM</title>
</head>
 
<body>
    <my-custom-element>
        <header>header</header>
        <main>
            <span>content</span>
        </main>
        <footer>footer</footer>
    </my-custom-element>
    <div id="slots">
        <!-- my-custom-element中的匿名标签都会放在第一个slot标签中 -->
        <slot></slot>
        <slot></slot>
        <slot></slot>
    </div>
 
    <script>
        const elemName = "my-custom-element"
        const ele = document.querySelector(elemName)
        const slots = document.querySelector("#slots")
        class MyCustomElement extends HTMLElement {
            constructor() {
                super()
                this.attachShadow({ mode: 'open' });
                this.shadowRoot.appendChild(slots)
            }
        }
        customElements.define(elemName, MyCustomElement)
    </script>
</body>
 
</html>

在页面中的DOM结构如下,三个标签都被放在了第一个slot

后备插槽

当我们使用图片标签图片却加载失败时往往会给图片增加一个alt文字提醒,或使用默认图片。类似的插槽也有这种效果。当我们使用具名插槽并且找不到对应的标签时,可以在slot标签中增加标签以便默认状态展示,比如

<!DOCTYPE html>
<html lang="en">
 
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ShadowDOM</title>
</head>
 
<body>
    <button>显示后备插槽</button>
    <my-custom-element>
        <div id="content" slot="content">具名插槽</div>
    </my-custom-element>
    <div id="slots">
        <slot name="content">
            <div style="color: lightcoral;">后备插槽</div>
        </slot>
    </div>
 
    <script src="./main.js"></script>
    <script>
        const content = document.querySelector("#content")
        document.querySelector("button").addEventListener("click", () => {
            content.remove()// 当自定义标签my-custom-element中没有标签时,则显示后备插槽标签
        })
    </script>
</body>
 
</html>

当我们将自定义标签中对应的插槽删掉时,插槽元素就会显示后备插槽标签

插槽更新

当我们插入,修改,移除插槽时会触发slotchange事件钩子,类似于用于监听DOM更新的MutationObserver,来看看下面的代码

<!DOCTYPE html>
<html lang="en">
 
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ShadowDOM</title>
</head>
 
<body>
    <my-custom-element-change>
        <div id="content" slot="content">插槽</div>
        <div id="content2" slot="content2">插槽2</div>
    </my-custom-element-change>
    <div id="slots">
        <slot name="content"></slot>
    </div>
    <script src="./main.js"></script>
    <script>
        const slot_box = `<div id="box1">slot</div>`
        const slot_content = slots?.querySelector('[name="content"]')
        slot_content.addEventListener("slotchange", console.log);
        customElements.define('my-custom-element-change', class extends MyCustomElement { });// 初始化触发slotchange
        setTimeout(() => slot_content.name = "content2", 1000)// 替换slot绑定的元素,触发slotchange
        setTimeout(() => slot_content.remove(), 2000)// 删除插槽触发slotchange
    </script>
</body>
 
</html>

上面的代码主要是一个简单的slotchange回调演示,创建自定义元素后,slot会初始化触发slotchange,1秒后修改slot内容触发slotchange,最后2秒后删除slot再次触发回调

插槽api

  • assignedSlot:它是标签的一个属性,通常在slot的目标标签使用,用于获取目标标签绑定的slot标签
  • assignedNodes:assignedNodes是slot上的函数,使用该方法可以返回所有分配的节点,包括文本节点和元素节点
  • assignedElements:assignedElements是slot上的函数,它会返回分配的元素节点
<!DOCTYPE html>
<html lang="en">
 
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ShadowDOM</title>
</head>
 
<body>
    <my-custom-element>
        text1
        <header slot="header">header</header>
        text2
        <main slot="content">
            content
            <span>content1</span>
            <span>content2</span>
            <span>
                <div>
                    <span>content3</span>
                </div>
            </span>
        </main>
        <footer slot="footer">footer</footer>
    </my-custom-element>
    <div id="slots">
        <slot name="header">header</slot>
        <slot name="content">content</slot>
        <slot name="footer">footer</slot>
    </div>
 
    <script src="./main.js"></script>
    <script>
        const elems = document.querySelectorAll('[slot]')
        const slotElems = slots.querySelectorAll('[name]')
        elems.forEach(it => console.log(it.assignedSlot))
        slotElems.forEach(slot => {
            const nodes = slot.assignedNodes();
            const elements = slot.assignedElements();
            nodes.forEach(console.log);
            elements.forEach(console.log);
        })
    </script>
</body>
 
</html>

总结

插槽是Web Components中的一个重要特性,用于在自定义组件内部定义占位符,使得父组件可以向其中插入内容,从而实现了组件之间的高度灵活的通信和组合。通过合理使用具名插槽、匿名插槽以及后备插槽,开发者可以实现高度定制化的组件组合。同时,插槽的事件和 API 提供了对插槽内容的监测和操作,为构建更加动态的用户界面增添了便利性。

以上就是文章全部内容了,如果觉得文章不错的话,还望三连支持一下,感谢!

相关文章
|
2月前
|
XML 缓存 JavaScript
提升对前端的认知,不得不了解Web API的DOM和BOM
该文章强调了在前端开发中理解和掌握DOM(文档对象模型)和BOM(浏览器对象模型)的重要性,并介绍了它们的相关操作和应用。
提升对前端的认知,不得不了解Web API的DOM和BOM
|
3月前
|
XML JavaScript 前端开发
哇塞!Web 前端惊现 DOM 元素神操作,一场惊心动魄的网页变革,你准备好了吗?
【8月更文挑战第23天】在Web前端开发中,熟练操作DOM元素至关重要。DOM作为一种编程接口,将HTML/XML文档表示为节点树,便于使用JavaScript访问及修改文档内容与结构。
56 0
|
3月前
|
XML JavaScript 测试技术
Web自动化测试框架(基础篇)--HTML页面元素和DOM对象
本文为Web自动化测试入门指南,介绍了HTML页面元素和DOM对象的基础知识,以及如何使用Python中的Selenium WebDriver进行元素定位、操作和等待机制,旨在帮助初学者理解Web自动化测试中的关键概念和操作技巧。
52 1
|
4月前
|
JavaScript 前端开发 API
Web Components详解-HTML Templates
Web Components详解-HTML Templates
75 6
|
4月前
|
设计模式 JavaScript 前端开发
Web Components详解-组件通信
Web Components详解-组件通信
78 6
|
4月前
|
JavaScript 前端开发
Web Components详解-Shadow DOM样式控制
Web Components详解-Shadow DOM样式控制
133 3
|
1月前
|
JavaScript
DOM 节点列表长度(Node List Length)
DOM 节点列表长度(Node List Length)
|
22天前
|
JavaScript
HTML DOM 节点树
HTML DOM 节点是指在 HTML 文档对象模型中,文档中的所有内容都被视为节点。整个文档是一个文档节点,每个 HTML 元素是元素节点,元素内的文本是文本节点,属性是属性节点,注释是注释节点。DOM 将文档表示为节点树,节点之间有父子和同胞关系。
|
22天前
|
JavaScript
HTML DOM 节点
HTML DOM(文档对象模型)将HTML文档视为节点树,其中每个部分都是节点:文档本身是文档节点,HTML元素是元素节点,元素内的文本是文本节点,属性是属性节点,注释是注释节点。节点间存在父子及同胞关系,形成层次结构。
|
1月前
|
XML JavaScript 数据格式
XML DOM 遍历节点树
XML DOM 遍历节点树