[Day08] - 弹跳视窗 Modal - Slot 介绍

网页元件中 , 常会使用 Modal 这种类型的元件

如果我们将其制作成一个 <Modal> 的 WebComponent , 之後在使用时 , 应该会轻松不少吧 !

下面我们来制作 <Modal> 吧 !


前期准备

one 我们先到 CodePen 下载今天的 Modal 范本

two 解压缩後 , 观察 html 中的 pop-up-container 结构

我们可以发现 Modal 的大致结构如下

<div class="pop-up-container" style="display: none;">
  <div class="pop-up-container-root">
    <div class="pop-up-box">
      <div class="pop-up-title">
        <h3>Title</h3>
        <close-icon/>
      </div>
      <div class="pop-up-content">
      </div>
      <div class="pop-up-action">
        <button onclick='closeModal()'>取消</button>
        <button onclick='closeModal()'>确定送出</button>
      </div>
    </div>
  </div>
</div>
区块名称 描述
pop-up-container Modal 的容器 , 黑底遮罩放在这 , 不会改变
pop-up-container-root Modal 的卷动区块 , 不会改变
pop-up-box Modal 的内容放在其中 , 不会改变
pop-up-title 标题区块 , 可能会修改其内容
pop-up-content 内文区块 , 可能会修改其内容
pop-up-action 按钮区域 , 可能会修改其内容

pop-up-title . pop-up-content . pop-up-action 这 3 个区块需要塞入 html 内容

Day02 介绍 wired-element 时 , 我们了解到 slot 可以塞入 html 内容

不过 , 需要区分 pop-up-title . pop-up-content . pop-up-action 3 个区块的 slot 要如何制作呢 ?

three Name Slot 的介绍

我们可以在 shadow-dom 中设定 <slot name="modal-body"> 在使用 <Modal> 时设定 slot="modal-body" ,

// in html usage 
<Modal>
  <h2 slot="modal-body">
    这是内文...这是内文...这是内文...这是内文...
  </h2>
</Modal>
// in web component 
class Modal extends HTMLElement {

  connectedCallback() {

    const htmlStr = `
        <div>
           其他文字
          <div class="pop-up-content">
            <h2 slot="modal-body">
              这是内文...这是内文...这是内文...这是内文...
            </h2>
          </div>
        </div>
    `

    // 启用 shadow dom
    this.attachShadow({mode: 'open'}).innerHTML = htmlStr
  }

}

window.customElements.define('my-modal', Modal);

Pink Tree 其实做法跟 Vue 的 Slot 是相似的

实作开始

one 建立 customElements - my-modal

class Modal extends HTMLElement {

}

window.customElements.define('my-modal', Modal);

twoshadow-dom 开启 & 将 html 结构复制到 class 中

class Modal extends HTMLElement {

  connectedCallback() {

    const styleStr = `<link rel="stylesheet" href="./modal.css">`

    const htmlStr = `
        <div class="pop-up-container" style="display: none;">
          <div class="pop-up-container-root">
            <div class="pop-up-box">
              <div class="pop-up-title flex justifyContent">
               <h3>这是 Modal 的 Title</h3>
                <img class='close' src="./close.png" />
              </div>
              <div class="pop-up-content">
                这是 Modal 的 Body
              </div>
              <div class="pop-up-action flex justifyContent">
                  <button class='close'>取消</button>
                  <button class='confirm'>确定送出</button>
              </div>
            </div>
          </div>
        </div>
    `

    // 启用 shadow dom
    this.attachShadow({mode: 'open'}).innerHTML = styleStr + htmlStr
  }

}

window.customElements.define('my-modal', Modal);

three 将 Name Slot 设定到 html 中

  • 将右侧的 3 区块 pop-up-title . pop-up-content . pop-up-action 设定对应的 slot
区块名称 Slot 名称
pop-up-title modal-title
pop-up-content modal-body
pop-up-action modal-action
<div class="pop-up-box">
  <div class="pop-up-title flex justifyContent">
+   <slot name="modal-title"><h3>这是 Modal 的 Title</h3></slot>
    <img class='close' src="" />
  </div>
  <div class="pop-up-content">
+    <slot name="modal-body">这是 Modal 的 Body</slot>
  </div>
  <div class="pop-up-action flex justifyContent">
+    <slot name="modal-action">
       <button class='close'>取消</button>
       <button class='confirm'>确定送出</button>
+    </slot>
  </div>
</div>

four 设定 Modal 的 open . close 事件

class Modal extends HTMLElement {

  connectedCallback() {

    this.attachShadow({mode: 'open'}).innerHTML = styleStr + htmlStr

    this.shadowRoot.querySelector('.close:nth-child(1)').addEventListener('click', () => this._close())
    this.shadowRoot.querySelector('.close:nth-child(2)').addEventListener('click', () => this._close())
    this.shadowRoot.querySelector('.confirm').addEventListener('click', () => this._confirm())
  }

  _open() {

    const shadowRoot = this.shadowRoot;
    const modalWrap = shadowRoot.querySelector('.pop-up-container');
    const popup = modalWrap.querySelector('.pop-up-box');

    modalWrap.style.display = 'flex';
    popup.style.transform = 'scale(0)';

    setTimeout(() => popup.style.transform = 'scale(1)', 0)
  }

  _close() {

    const shadowRoot = this.shadowRoot;
    const modalWrap = shadowRoot.querySelector('.pop-up-container');
    const popup = modalWrap.querySelector('.pop-up-box');

    popup.style.transform = 'scale(0)';

    setTimeout(() => modalWrap.style.display = 'none', 300)
  }
  
}

window.customElements.define('my-modal', Modal);

five 在页面中使用 my-modal

<body>
<my-modal @confirm="() => console.log('确定送出 !')">
  <h2 slot="modal-title">
    表头写入
  </h2>
  <h2 slot="modal-body">
    这是内文...这是内文...这是内文...这是内文...
  </h2>
</my-modal>

<script src="./modal-wc.js"></script>
</body>
</html>

six 建立按钮来开启今天制作的 Modal

<button onclick='showModal()'>
  开启 Modal
</button>
<script>
  function showModal() {
    document.querySelector('my-modal')._open()
  }
</script>

完成 !!

成果

如果想直接体验成果 , 请到 web-component-modal.html 查看

题外话

其实 HTML Tag 有一个 <dialog> 跟今天制作的元件很相似

参考资料 :


<<:  案例:AWS MLOps Framework - 解决方案介绍

>>:  Azure - Day6 Azure Function

【2022 Mac必学】五 个方法救回 Word 当机未保存的文档

软件当机每次来得都是猝不及防,Word 也不例外。辛辛苦苦在 Word 编辑的文档因突然当机丢失了,...

用React刻自己的投资Dashboard Day15 - 投资Dashboard 2.0版 Wireframe

有了总体经济的图表之後,接下来就要来制作各国股市的资讯站,笔者最常看的就是台股的资讯,其次则是美股、...

Day16-TypeScript(TS)在类别(Class)实作介面(Interface)

今天要来介绍类别实作介面, 介面型别我觉得很大的一个优势是可以重复使用, 因此我们就来说说这个吧。 ...

[Day07] swift & kotlin 入门篇!(5) 基础语法-集合物件

集合物件 集合物件代表 "一个放置一堆东西的地方" 它可以是有序 有可以是无序的...

[Part 7 ] Vue.js 的精随-元件生命周期 (续)

摧毁阶段 这个阶段负责元件的移除,适合用来移除所有的事件监听以及任何会造成记忆体泄漏(memory ...