前言
插槽实际上也属于组件通信的一种方式,但是由于其强大的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 提供了对插槽内容的监测和操作,为构建更加动态的用户界面增添了便利性。
以上就是文章全部内容了,如果觉得文章不错的话,还望三连支持一下,感谢!