【问题标题】:Custom HTML elements自定义 HTML 元素
【发布时间】:2017-03-27 20:03:49
【问题描述】:

HTML spec 描述了存储在 CustomElementRegistry 中的几种元素。

  1. <a> 这样的内置元素,由 HTMLElement 的内置子类表示,如 HTMLAnchorElement
  2. 自主自定义元素,如 <my-element>,扩展 HTMLElement 并在 CustomElementRegistry 中注册。
  3. Customized builtin elements<a is="my-link"> 类似,它扩展了 HTMLElement 的子类并使用 is="customized-tag-name" 指定类。
  4. Legacy elements<isindex> 一样扩展了 HTMLUnknownElement
  5. Customizable elements 尚未(尚未?)注册可能是由于脚本加载延迟。

有没有办法在运行时确定一个元素属于哪个存储桶?

【问题讨论】:

    标签: html web-component custom-element


    【解决方案1】:

    下面的 [jsbin] 可以在不测试 "[native code]" 的构造函数的情况下完成工作和管理,但必须有更好的方法来判断元素是否是内置的。

    //<script>
    
    // https://w3c.github.io/webcomponents/spec/custom/#valid-custom-element-name
    var VALID_CUSTOM_ELEMENT_NAME_REGEX = /^(?!(?:annotation-xml|color-profile|font-face|font-face(?:-(?:src|uri|format|name))?|missing-glyph)$)[a-z][a-z.0-9_\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u200C\u200D\u203F-\u2040\u2070-\u218F\u2C00-\u2FEF\u3001-\uDFFF\uF900-\uFDCF\uFDF0-\uFFFD]*-[\-a-z.0-9_\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u200C\u200D\u203F-\u2040\u2070-\u218F\u2C00-\u2FEF\u3001-\uDFFF\uF900-\uFDCF\uFDF0-\uFFFD]*$/;
    
    function classify(el) {
      var name = el.localName;
      // TODO: are elements from a different document dealt with by that
      // document's CustomElementRegistry?
      // How do we get from a document to a CustomElementRegistry?
      // Maybe just assert el.ownerDocument === document?
      // Does that screw up elements from <template> content.
      if (customElements.get(name)) { return 'custom'; }
      // TODO: check that the value of is="..." is registered
      if (el.getAttribute('is')) { return 'custom-builtin'; }
      var ctor = el.constructor;
      if (ctor === HTMLUnknownElement) { return 'legacy'; }
      if (ctor === HTMLElement) {
        if (VALID_CUSTOM_ELEMENT_NAME_REGEX.test(name)) {
          return 'customizable';
        }
      }
      return 'builtin';
    }
    
    
    // A bunch of element names from MDN and elsewhere to test
    var names = [
      "a", "abbr", "acronym", "address", "applet",
      "annotation-xml", "area",
      "article", "aside", "audio", "b", "base", "basefont", "bdi", "bdo",
      "bgsound", "big", "blink", "blockquote", "body", "br", "button",
      "canvas", "caption", "center", "cite", "code", "col", "colgroup",
      "command", "content", "data", "datalist", "dd", "del", "details",
      "dfn", "dialog", "dir", "div", "dl", "dt", "element", "em", "embed",
      "fieldset", "figcaption", "figure", "font", "footer", "form",
      "frame", "frameset", "h1", "h6", "head", "header", "hgroup", "hr",
      "html", "i", "iframe", "image", "img", "input", "ins", "isindex",
      "kbd", "keygen", "label", "legend", "li", "link", "listing", "main",
      "map", "mark", "marquee", "menu", "menuitem", "meta", "meter",
      "multicol", "nav", "nobr", "noembed", "noframes", "noscript",
      "object", "ol", "optgroup", "option", "output", "p", "param",
      "picture", "plaintext", "pre", "progress", "q", "rp", "rt", "rtc",
      "ruby", "s", "samp", "script", "section", "select", "shadow",
      "slot", "small", "source", "spacer", "span", "strike", "strong",
      "style", "sub", "summary", "sup", "table", "tbody", "td",
      "template", "textarea", "tfoot", "th", "thead", "time", "title",
      "tr", "track", "tt", "u", "ul", "var", "video", "wbr", "xmp",
      "isindex",  // Known legacy element
      "un-registered", "reg-istered"];  // Test custom / customizable
    
    //</script><script>
    
    class MyElement extends HTMLElement {
      constructor() {
        super();
      }
    }
    
    customElements.define('reg-istered', MyElement);
    
    //</script><script>
    var table = document.createElement('table');
    document.body.appendChild(table);
    var tbody = document.createElement('tbody');
    table.appendChild(tbody);
    function addRowForElement(el) {
      var tr = document.createElement('tr');
      tbody.appendChild(tr);
      var td0 = document.createElement('td');
      tr.appendChild(td0);
      td0.appendChild(document.createTextNode(el.outerHTML));
      var td1 = document.createElement('td');
      tr.appendChild(td1);
      td1.appendChild(document.createTextNode('' + classify(el)));
    }
    for (var i = 0, n = names.length; i < n; ++i) {
      addRowForElement(document.createElement(names[i]));
    }
    var customBi = document.createElement('input');
    customBi.setAttribute('is', 'my-custom-input');  // Not yet registered.
    addRowForElement(customBi);
    //</script><style>td:first-child { font-family: monospace }</style>
    

    【讨论】:

    • (customElements.get()) 也将返回 true 用于注册的自定义内置元素。
    猜你喜欢
    • 2017-06-02
    • 2019-12-11
    • 1970-01-01
    • 1970-01-01
    • 2014-09-20
    • 2021-12-09
    • 2019-01-30
    • 2012-11-11
    • 1970-01-01
    相关资源
    最近更新 更多