You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

动态生成的details元素无法展开至完整尺寸问题求助

动态生成的details元素无法展开至完整尺寸问题求助

我正在做一个纯JavaScript生成的菜单,按照社区里大家的建议实现后遇到了个问题:动态生成的菜单没办法展开到完整尺寸,里面的文本内容完全显示不出来。实际显示效果是只看到一个小的summary按钮,展开后也看不到下方的选项文本;但预期应该是展开后能完整展示所有带文本的复选框选项,所有元素的属性和文本内容我都确认过是正确填充的。

我对比了两种实现,唯一的区别就是:出问题的版本是完全动态生成模板的,而能正常工作的版本是静态构建的模板。

完整代码实现

class GLMenuTemplate {
  #style_id = "webgl_menu_template_style";
  #template_id = "webgl_menu_template";
  #webgl_css = `
div.webgl_menu /*element.class*/ {
 position:absolute;z-index:10;border:1px solid black;
}
div.webgl_menu summary /*element.class elements*/ {
 background-color: #eee;
 width: 1.3em;
 height: 1.3em;
 border: solid black thin;
 border-radius: .3em;
 padding: 0;
 margin: 0;
 align-content: center;
 text-align: center;
 cursor: pointer;
}
div.webgl_menu summary::marker {
 content: "+";
} /*element.class elements*/
div.webgl_menu summary:hover {
 background-color:#ddd;
}
div.webgl_menu details[open] summary::marker {
 content: "x";
}`;

  constructor () {
    this.#styleInit();
    this.#templateInit();
  }

  get template () {return document.getElementById(this.#template_id);}

  #styleInit() {
    if (document.getElementById (this.#style_id)) return;
    let style = document.createElement("style");
    style.setAttribute ("id", this.#style_id);
    style.textContent = this.#webgl_css;
    document.body.appendChild(style);
  }

  #templateInit() {
    if (document.getElementById (this.#template_id)) return;
    let div = this.#createDiv();
    let tr = this.#createTr();
    let template = this.#createTemplate (this.#template_id, [div, tr]);
    document.body.appendChild(template);
  }

  #createElement(elementName, children) {
    let element = document.createElement (elementName);
    if (children) for (let child of children) element.appendChild (child);
    return element;
  }

  #createTemplate(id, contents) {
    let template = document.createElement("template");
    template.setAttribute ("id", id);
    document.body.appendChild(template);
    if (contents) for (let content of contents) template.content.appendChild(content);
    return template;
  }

  #createDiv() {
    //template for menu item <tr><td><label><input>
    let summary = document.createElement ("summary");
    let table = document.createElement ("table");
    //table.appendChild(tr);
    let details = this.#createElement ("details", [summary, table]);
    let div = this.#createElement ("div", [details]);
    div.setAttribute ("class", "webgl_menu");
    return div;
  }

  #createTr () {
    let label = this.#createElement ("label");
    let td = this.#createElement ("td", [label] );
    let tr = this.#createElement ("tr", [td]);
    return tr;
  }
}

class GLMenu {
  #x = 0xffff;
  #y = 0xffff;
  #rowt = null;
  #items = null;
  #tpl = null;

  constructor (x, y, relativeElement) {
    let menuTemplate = new GLMenuTemplate();
    this.#template = menuTemplate.template;
    [this.#x, this.#y] = [window.scrollX + x, window.scrollY + y];
    if (relativeElement) {
      let r = relativeElement.getBoundingClientRect();
      this.#x += r.left;
      this.#y += r.top;
    }
    let divt = {div: this.#template.content.querySelector("div")};
    let dive = {div: document.importNode(divt.div, true)};
    [dive.div.style.top, dive.div.style.left] = [this.#y, this.#x];
    document.body.appendChild(dive.div);
    this.#rowt = {tr: this.#template.content.querySelector("tr")};
    this.#items = dive.div.querySelector ("table");
  }

  set #template(value) { this.#tpl = value; }
  get #template() { return this.#tpl; }

  attachEventListeners(element, listeners) {
    if (!listeners) return;
    if (typeof listeners === "function") {
      element.addEventListener ("click", listeners);
      return;
    }
    if (Array.isArray(listeners)) {
      for (let listener of listeners) element.addEventListener (listener.name, listener.callback);
      return;
    }
    element.addEventListener (listeners.name, listeners.callback);
  }

  addCheckbox (text, events) {
    let input = document.createElement ("input");
    input.setAttribute ("type", "checkbox");
    input.textContent = text;
    this.attachEventListeners (input, events);
    let rowe = {tr: document.importNode(this.#rowt.tr, true)};
    let label = rowe.tr.querySelector("label");
    label.appendChild (input);
    this.#items.appendChild (rowe.tr);
    return input;
  }
}

document.addEventListener('DOMContentLoaded', (event) => {
  let menu1 = new GLMenu(10, 10);
  menu1.addCheckbox ("write to console", [{name:"click", callback: (e) => {
    console.log (e.target.textContent + ": checked:" + e.target.checked);
  }}] );
  menu1.addCheckbox ("don't write to console", (e) => {
    console.log (e.target.textContent + ": don't, checked:" + e.target.checked);
  } );

  //Menu 2
  let menu2 = new GLMenu(100, 100);
  menu2.addCheckbox ("write to console 2", {name:"click", callback: (e) => {
    console.log (e.target.textContent + ": 2 checked:" + e.target.checked);
  }} );
  menu2.addCheckbox ("don't write to console 2", (e) => {
    console.log (e.target.textContent + ": don't 2, checked:" + e.target.checked);
  } );
});

我已经检查过:

  • 样式表正确加载到页面中了
  • 所有DOM元素都正确创建并挂载到了页面上
  • 复选框的文本内容也正确设置了

但就是展开后菜单尺寸不对,看不到文本内容,有没有大佬能帮忙看看问题出在哪里呀?

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.08 07:13:03