【问题标题】:web component - accept no child elementsWeb 组件 - 不接受子元素
【发布时间】:2019-05-29 23:32:59
【问题描述】:

如何定义一个像<img> 一样工作的 Web 组件,因为它不接受子元素?

  <script>
    const QA = (q, d) => Array.prototype.slice.call((d||document).querySelectorAll(q), 0);
    const QS = (q, d) => (d||document).querySelector(q);
  </script>

  <template id="push-message">
    <style>
      message { display: grid; font-family: sans-serif; background: #eee; outline: 1px solid; }
      .badge {  }
    </style> 
    <message>
      <img class="badge">
      <img class="icon">
      <img class="image">
    </message>
  </template>

  <script>    
    const wpm = 'push-message';
    customElements.define(wpm,
      class extends HTMLElement {
        constructor() { 
          super();
          const l = QS(`#${wpm}`).content.cloneNode(true);
          const s = this.attachShadow({ mode: 'open' }); s.appendChild(l);
        }
        QS(q) { return QS(q, this.shadowRoot); }
        QA(q) { return QA(q, this.shadowRoot); }  
        static get observedAttributes() { return [ "badge", "icon", "image" ]; }
        attributeChangedCallback(a, o, n) {
          if (/^(badge|icon|image)$/.test(a))
            this.QS(`.${a}`).src = n;
        }
      });
  </script>

  <push-message 
     badge="//google.com/favicon.ico"
      icon="//google.com/favicon.ico"
     image="//google.com/favicon.ico">
  <p>ok</p>

DOM 应该是

<push-message></push-message>
<p></p>

不是

<push-message><p></p></push-message>

ok 应该会显示在结果中。


有没有办法更改 customElements.define 以避免必须显式关闭 &lt;push-message&gt;&lt;/push-message&gt; 并只使用 &lt;push-message&gt; 但隐式地自行关闭?

【问题讨论】:

  • 虽然你现在不能这样做,但它肯定是一个不错的升级。而且,它不应该真的那么难实现。只需在调用define 时添加一个选项。

标签: html dom web-component


【解决方案1】:

自治自定义元素需要一个结束标签:Do custom elements require a close tag?

您可以创建从 HTMLImageElement 扩展而来的自定义内置元素
获得一个自动关闭的 IMG 标签:

<img is="push-message" badge="//google.com/favicon.ico">
<img is="push-message" icon="//google.com/favicon.ico">
<img is="push-message" image="//google.com/favicon.ico">
<p>ok</p>

但是一个IMG只能有一个src,所以你不妨创建3个元素并使用

<img is="message-badge">
<img is="message-icon">
<img is="message-image">

【讨论】:

    【解决方案2】:

    自闭标签,称为void elements

    AFAIK,无法创建自定义 void 元素。总之,它需要改变浏览器的 HTML 解析器,这不是一件容易被网络社区拉动的事情。由于浏览器实现tag-soup algorithm 的方式,需要进行更改。

    因此您需要一个结束标签。您可以在此处阅读更多相关信息:

    附带说明,如果您有自己的模板编译器/解析器,例如 vue-compilerng-compiler,您可能可以指示它在构建时了解自关闭自定义元素。然而,实现这一点的好处几乎不存在。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-06-04
      • 2013-09-24
      • 1970-01-01
      • 2021-11-26
      • 2022-01-16
      • 2023-02-08
      • 2016-01-28
      • 1970-01-01
      相关资源
      最近更新 更多