• Web Components详解-Shadow DOM插槽


    前言

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

    定义

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

    基本用法

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

    插槽标签的写法

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

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

    1. <my-custom-element>
    2. <div slot="标签slot属性值">标签div>
    3. my-custom-element>

    完整示例参考下面的代码

    1. html>
    2. <html lang="en">
    3. <head>
    4. <meta charset="UTF-8">
    5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
    6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
    7. <title>ShadowDOMtitle>
    8. head>
    9. <body>
    10. <my-custom-element>
    11. <header slot="header">headerheader>
    12. <main slot="content">
    13. <span>contentspan>
    14. main>
    15. <footer slot="footer">footerfooter>
    16. my-custom-element>
    17. <div id="slots">
    18. <slot name="header">slot>
    19. <slot name="content">slot>
    20. <slot name="footer">slot>
    21. div>
    22. <script>
    23. const elemName = "my-custom-element"
    24. const ele = document.querySelector(elemName)
    25. const slots = document.querySelector("#slots")
    26. class MyCustomElement extends HTMLElement {
    27. constructor() {
    28. super()
    29. this.attachShadow({ mode: 'open' });
    30. this.shadowRoot.appendChild(slots)// 插槽必须在shadowDOM中
    31. }
    32. }
    33. customElements.define(elemName, MyCustomElement)
    34. script>
    35. body>
    36. html>

    具名插槽

    具名插槽实际上就是上面的用法,在自定义标签中使用

    标签
    以及在影子DOM中使用的形式达到效果

    DOM的结构如下

    匿名插槽

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

    1. html>
    2. <html lang="en">
    3. <head>
    4. <meta charset="UTF-8">
    5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
    6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
    7. <title>ShadowDOMtitle>
    8. head>
    9. <body>
    10. <my-custom-element>
    11. <header>headerheader>
    12. <main>
    13. <span>contentspan>
    14. main>
    15. <footer>footerfooter>
    16. my-custom-element>
    17. <div id="slots">
    18. <slot>slot>
    19. <slot>slot>
    20. <slot>slot>
    21. div>
    22. <script>
    23. const elemName = "my-custom-element"
    24. const ele = document.querySelector(elemName)
    25. const slots = document.querySelector("#slots")
    26. class MyCustomElement extends HTMLElement {
    27. constructor() {
    28. super()
    29. this.attachShadow({ mode: 'open' });
    30. this.shadowRoot.appendChild(slots)
    31. }
    32. }
    33. customElements.define(elemName, MyCustomElement)
    34. script>
    35. body>
    36. html>

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

    后备插槽

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

    1. html>
    2. <html lang="en">
    3. <head>
    4. <meta charset="UTF-8">
    5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
    6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
    7. <title>ShadowDOMtitle>
    8. head>
    9. <body>
    10. <button>显示后备插槽button>
    11. <my-custom-element>
    12. <div id="content" slot="content">具名插槽div>
    13. my-custom-element>
    14. <div id="slots">
    15. <slot name="content">
    16. <div style="color: lightcoral;">后备插槽div>
    17. slot>
    18. div>
    19. <script src="./main.js">script>
    20. <script>
    21. const content = document.querySelector("#content")
    22. document.querySelector("button").addEventListener("click", () => {
    23. content.remove()// 当自定义标签my-custom-element中没有标签时,则显示后备插槽标签
    24. })
    25. script>
    26. body>
    27. html>

     

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

    插槽更新

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

    1. html>
    2. <html lang="en">
    3. <head>
    4. <meta charset="UTF-8">
    5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
    6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
    7. <title>ShadowDOMtitle>
    8. head>
    9. <body>
    10. <my-custom-element-change>
    11. <div id="content" slot="content">插槽div>
    12. <div id="content2" slot="content2">插槽2div>
    13. my-custom-element-change>
    14. <div id="slots">
    15. <slot name="content">slot>
    16. div>
    17. <script src="./main.js">script>
    18. <script>
    19. const slot_box = `
      slot
      `
    20. const slot_content = slots?.querySelector('[name="content"]')
    21. slot_content.addEventListener("slotchange", console.log);
    22. customElements.define('my-custom-element-change', class extends MyCustomElement { });// 初始化触发slotchange
    23. setTimeout(() => slot_content.name = "content2", 1000)// 替换slot绑定的元素,触发slotchange
    24. setTimeout(() => slot_content.remove(), 2000)// 删除插槽触发slotchange
    25. script>
    26. body>
    27. html>

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

    插槽api

    • assignedSlot:它是标签的一个属性,通常在slot的目标标签使用,用于获取目标标签绑定的slot标签
    • assignedNodes:assignedNodes是slot上的函数,使用该方法可以返回所有分配的节点,包括文本节点和元素节点
    • assignedElements:assignedElements是slot上的函数,它会返回分配的元素节点
    1. html>
    2. <html lang="en">
    3. <head>
    4. <meta charset="UTF-8">
    5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
    6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
    7. <title>ShadowDOMtitle>
    8. head>
    9. <body>
    10. <my-custom-element>
    11. text1
    12. <header slot="header">headerheader>
    13. text2
    14. <main slot="content">
    15. content
    16. <span>content1span>
    17. <span>content2span>
    18. <span>
    19. <div>
    20. <span>content3span>
    21. div>
    22. span>
    23. main>
    24. <footer slot="footer">footerfooter>
    25. my-custom-element>
    26. <div id="slots">
    27. <slot name="header">headerslot>
    28. <slot name="content">contentslot>
    29. <slot name="footer">footerslot>
    30. div>
    31. <script src="./main.js">script>
    32. <script>
    33. const elems = document.querySelectorAll('[slot]')
    34. const slotElems = slots.querySelectorAll('[name]')
    35. elems.forEach(it => console.log(it.assignedSlot))
    36. slotElems.forEach(slot => {
    37. const nodes = slot.assignedNodes();
    38. const elements = slot.assignedElements();
    39. nodes.forEach(console.log);
    40. elements.forEach(console.log);
    41. })
    42. script>
    43. body>
    44. html>

    总结

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

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

    相关代码

    myCode: 基于js的一些小案例或者项目 - Gitee.com

    参考文章

    Shadow DOM 插槽,组成

  • 相关阅读:
    Python 支付宝红包二维码制作步骤分享
    Java-io(输入/输出)
    卷起来了?2023这三个项目直接让你原地起飞!
    电路电子技术3 电位的计算&受控源在电路分析中的作用
    使用jmeter进行接口测试
    <SQL编程工具MySQL、SQLyog安装及环境配置教程>——《SQL》
    业务安全相关安全产品的反思
    React TypeScript .d.ts为后缀文件
    Linux安装mysql5.7
    【毕业设计】基于javaEE+原生Servlet+MySql的网络考试系统设计与实现(毕业论文+程序源码)——网络考试系统
  • 原文地址:https://blog.csdn.net/time_____/article/details/132107559