astro中建立web components

卓能文發表於2024-08-07

MyCounter.astro:

<script>
const template = `
  <style>
    * {
      font-size: 200%;
    }

    span {
      width: 4rem;
      display: inline-block;
      text-align: center;
    }

    button {
      width: 4rem;
      height: 4rem;
      border: none;
      border-radius: 10px;
      background-color: seagreen;
      color: white;
    }
  </style>

  <button id="dec">-</button>
  <span id="count"></span>
  <button id="inc">+</button>
`;

class MyCounter extends HTMLElement {
  count: number = 0;
  shadowRoot: ShadowRoot | null = null;

  constructor() {
    super();

    const elem = document.createElement("template");
    elem.innerHTML = template;

    this.shadowRoot = this.attachShadow({ mode: "open" });
    this.shadowRoot.appendChild(
      elem.content.cloneNode(true)
    );
  }

  connectedCallback() {
    this.shadowRoot!.getElementById("inc")!.onclick = () => this.inc();
    this.shadowRoot!.getElementById("dec")!.onclick = () => this.dec();
    this.update(this.count);
  }

  inc() {
    this.update(++this.count);
  }

  dec() {
    this.update(--this.count);
  }

  update(count: number) {
    this.shadowRoot!.getElementById("count")!.innerHTML = count.toString();
  }
}

customElements.define("my-counter", MyCounter);
</script>

test.mdx:

---
title: Welcome to Starlight
description: Get started building your docs site with Starlight.
template: splash
---

# Welcome

import "../../components/MyCounter.astro";

<my-counter />

注意,只能採用這種形式渲染:

import "../../components/MyCounter.astro";
<my-counter />

而不能採用:

import MyCounter from "../../components/MyCounter.astro";
<MyCounter />

否則,控制元件不顯示任何內容!!!

透過瀏覽器偵錯程式可以看到所有html元素都放在一個shadow-root之下。

相關文章