代码之家  ›  专栏  ›  技术社区  ›  Mike 'Pomax' Kamermans

如何正确地可视化嵌套HTML自定义元素

  •  0
  • Mike 'Pomax' Kamermans  · 技术社区  · 6 年前

    我正在尝试编写一个简单的HTML自定义元素,用于在页面上放置树,使用以下简单代码:

    <html-tree title="root">
      <tree-node title="child1">
        <tree-node title="leaf1"></tree-node>
        <tree-node title="leaf2"></tree-node>
      </tree-node>
      <tree-node title="child2">
        <tree-node title="leaf3"></tree-node>
        <tree-node title="leaf4"></tree-node>
      </tree-node>
    </html-tree>
    

    每个元素基本上都是一个带有单个未命名元素的阴影dom <slot></slot> 把孩子放进去,所以我希望有一个漂亮的嵌套结构。相反,如果我指定标准调试样式 :host>* { border:1px red solid; } 对于这些自定义元素,每个元素都显示在自己的行上,周围有一个边框,而不是将它们显示为嵌套的。

    如何以一种CSS很好的方式保留标记指定的嵌套?

    一个片段:

    /**
     * Main tree node class
     */
    class GenericNode extends HTMLElement {
      constructor() {
        super();
        this._shadow = enrich(this.attachShadow({mode: `open`}));
        this._shadow.addSlot = () => this._shadow.add(create(`slot`));
        if (!this.get) {
          this.get = e => this.getAttribute(e);
        }
        this.setupDOM(this._shadow);
      }
      setupDOM(shadow) {    
        this.setStyle(`:host>* { border:1px red solid; }`)
        if (this.leadIn) this.leadIn(shadow);
        shadow.addSlot();    
        if (this.leadOut) this.leadOut(shadow);
      }
      setStyle(text) {
        if (!this._style) {
          this._style = create(`style`, text);
          this._shadow.add(this._style);
        } else {
          this._style.textContent = text;
        }
      }
    }
    
    
    /**
     * "not the root" element
     */
    class Node extends GenericNode {
      constructor() {
        super();
      }
      leadIn(shadow) {
        shadow.add(create(`p`, this.get(`title`)));
      }
    }
    
    // register the component
    customElements.define(`tree-node`, Node);
    
    /**
     * "the root" element, identical to Node, of course.
     */
    class Tree extends Node  {
      constructor() {
        super();
      }
    }
    
    // register the component
    customElements.define(`html-tree`, Tree);
    
    
    /**
     * utility functions
     */
    
    function enrich(x) {
      x.add = e => x.appendChild(e);
      x.remove = e => {
        if (e) x.removeChild(e);
        else e.parentNode.removeChild(e);
      };
      x.get = e => x.getAttribute(x);  
      return x;
    }
    
    function find(qs) {
      return Array.from(
        document.querySelectorAll(qs).map(e => enrich(e))
      );
    }
    
    function create(e,c) {
      let x = enrich(document.createElement(e));
      x.textContent = c;
      return x;
    };
    <html-tree title="root">
      <tree-node title="child1">
      <tree-node title="leaf1"></tree-node>
        <tree-node title="leaf2"></tree-node>
      </tree-node>
      <tree-node title="child2">
        <tree-node title="leaf3"></tree-node>
        <tree-node title="leaf4"></tree-node>
      </tree-node>
    </html-tree>
    0 回复  |  直到 6 年前
        1
  •  1
  •   Mike 'Pomax' Kamermans    6 年前

    结果显示,阴影dom的默认样式及其内容为“nothing”,因此为了实现真正的嵌套, you need to force display:block or be similarly explicit .

    在上面的代码中,而不仅仅是在 :host>* 这个 :host ,以及 <slot> 还需要明确标记为块:

    setupDOM(shadow) {    
      this.setStyle(`
        :host {
          display: block;
          border: 1px red solid;
        }
        :host > slot {
          display: block;
          border: 1px red solid;
          margin-left: 1em;
        }
      `);
      ...
    }