javascript 自定义HTML元素在HTML树中成功呈现时,不会在屏幕上呈现

yquaqz18  于 2023-09-29  发布在  Java
关注(0)|答案(1)|浏览(85)

我创建了一个自定义HTML元素:

class PieChart extends HTMLElement {
    constructor() {
        super();
    } 

    init() {
        this.#render();
    }

    #render() {
        const circleElement = document.createElement("circle");
        circleElement.setAttribute("cx", 100);
        circleElement.setAttribute("cy", 100);
        circleElement.setAttribute("r", 80);
        circleElement.setAttribute("fill", "none");
        circleElement.setAttribute("stroke", "green");
        circleElement.setAttribute("stroke-width", 40);
        circleElement.setAttribute("stroke-dasharray", `502.85 502.85`);

        const svgElement = document.createElement("svg");
        svgElement.style.display = "block";
        svgElement.style.width = "inherit";
        svgElement.style.height = "inherit";
        svgElement.setAttribute("viewBox", `0 0 200 200`);
        svgElement.append(circleElement);

        this.appendChild(svgElement);

        this.style.display  = "block";
        this.style.width = "200px";
        this.style.height = "200px";
    }

    connectedCallback() {
        const event = new CustomEvent("init", {
            bubbles: true
        });
        this.dispatchEvent(event);
    }
}

customElements.define(
    "pie-chart",
    PieChart
);
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title></title>
    <link rel="stylesheet" href="./css/site.css" />
</head>
<body>
    <p>Hello!</p>
    <pie-chart></pie-chart>
</body>
</html>
<script>
    document.body.addEventListener("init", (pEvent) => {
        const element = pEvent.target;
        element.init(this);
    });
</script>

这段代码的执行没有任何问题,自定义元素在DOM中呈现。但是,该圆不会呈现在屏幕上。

PS:如果我在浏览器中打开DOM,点击PieChart元素上的“编辑为HTML”,并更改其中的任何内容并保存它,圆圈就会出现。我以前用过几次这种模式,都没有问题,但这一次是我第一次使用SVG元素。

7lrncoxx

7lrncoxx1#

这是not really how you create a custom element。在connectedCallback中创建一个shadow DOM,浏览器会完成其余的工作,包括“激活”在您注册标签时页面上已经存在的任何自定义元素。没有自定义事件调度,自定义元素系统旨在为您解决这个问题。

const createSVGElement = tag => document.createElementNS(`http://www.w3.org/2000/svg`, tag);

class PieChart extends HTMLElement {
  constructor() {
    super();
  } 

  connectedCallback() {
    console.log(`let's go`);
    const shadow = this.attachShadow({ mode: "open" });

    const circleElement = createSVGElement("circle");
    circleElement.setAttribute("cx", 100);
    circleElement.setAttribute("cy", 100);
    circleElement.setAttribute("r", 80);
    circleElement.setAttribute("fill", "none");
    circleElement.setAttribute("stroke", "green");
    circleElement.setAttribute("stroke-width", 40);
    circleElement.setAttribute("stroke-dasharray", "502.85 502.85");

    const svgElement = createSVGElement("svg");
    svgElement.setAttribute("viewBox", "0 0 200 200");
    svgElement.append(circleElement);

    shadow.appendChild(svgElement);
      
    const style = document.createElement("style");
    style.textContent = `
      svg {
        display: block;
        width: 200px;
        height: 200px;
      }
    `;
    
    shadow.appendChild(style);
  }
}

customElements.define("pie-chart", PieChart);
<pie-chart></pie-chart>

如果你使用SVG:请记住,即使SVG自HTML5以来就是“HTML的一部分”,JS端的SVG元素仍然需要使用SVG命名空间的document.createElementNS。超级奇怪,超级不方便,但我们还是坚持住了.

相关问题