Skip to content

用 Web Components 开发一个 dialog 组件

Posted on:2022年6月29日 at 18:28

关于Web Components > Vite为工程依赖 Ts语言开发

<!-- index.html -->
<body>
  <button class="open">open</button>
  <my-dialog>
    <h1>wo cao nb</h1>
  </my-dialog>

  <script type="module" src="./src/index.ts"></script>
</body>
/* ./src/index.ts */
class MyDialog extends HTMLElement {
  static componentName: string = "my-dialog";
  private closeButton: HTMLButtonElement;
  constructor() {
    super();
    const style = `
        :host(:not([open])) {
            display: none;
        }
        :host {
            position: fixed;
            left: 0; top: 0;
            height: 100%; width: 100%;
            background-color: rgba(25, 28, 34, 0.88);
            z-index: 19;
            display: grid;
            place-items: center;
        }
        dialog {
            position: static;
            display: inherit;
        }
        `;

    const html = `
        <style>${style}</style>
        <dialog>
            <!-- slot 插槽 作用与 Vue 的 slot 相同-->
            <slot>暂无提示信息</slot>
            <p>
                <button name="close">确定</button>
            </p>
        </dialog>
        `;
    // 解析html 字符串
    const template = document.createRange().createContextualFragment(html);
    const shadowRoot = this.attachShadow({ mode: "open" });
    shadowRoot.append(template);

    this.closeButton = this.shadowRoot.querySelector('button[name="close"]');

    this.closeButton.addEventListener("click", this.hide.bind(this));
  }

  hide() {
    this.toggleAttribute("open", false);
  }

  // 连接到 DOM
  connectedCallback() {
    /**
     * 一种常见错误是将 connectedCallback 用做一次性的初始化事件,
     * 然而实际上你每次将节点连接到 DOM 时都会被调用。
     * 取而代之的,
     * 在 constructor 这个 API 接口调用时做一次性初始化工作会更加合适。
     */
  }

  // 从 DOM 上脱离
  disconnectedCallback() {
    this.closeButton.removeEventListener("click", this.hide.bind(this));
  }
}
window.customElements.define(MyDialog.componentName, MyDialog);

const onLoaded = () => {
  const $ = {
    open: document.querySelector(".open"),
    dialog: document.querySelector("my-dialog"),
  };

  $.open.addEventListener("click", () => {
    $.dialog.toggleAttribute("open", true);
  });
};

window.addEventListener("load", onLoaded);

image