webcomponents.js Shadow DOM: селектор хоста не работает в Safari и Firefox

Я попытался создать свой собственный веб-компонент с помощью полифилла из https://github.com/webcomponents/webcomponentsjs.

Вот мой код:

им-список.html

<template id="im-list-temp">
  <style>
    :host {
      list-style-type: none;
      margin: 0;
      padding: 0;
    }
  </style>
  <content> </content>
</template>

<script>
  var currentScript = document._currentScript || document.currentScript;
  var proto = Object.create(HTMLUListElement.prototype, {
    createdCallback: {
      value: function() {
        var doc = currentScript.ownerDocument;
        var t = doc.querySelector("#im-list-temp");
        var clone = doc.importNode(t.content, true);
        var root = this.createShadowRoot();
        root.appendChild(clone);
      }
    }
  });
  document.registerElement('im-list', {
    prototype: proto,
    extends: 'ul'
  });
</script>

index.html

<!DOCTYPE html>
<html>
  <head>
    <script src="bower_components/webcomponentsjs/webcomponents.js"></script>
    <link rel="import" href="./components/im-list.html" />
    <title>List Test</title>
  </head>
  <body>
    <ul is="im-list">
      <li>Blubb</li>
      <li>Blubb Blubb</li>
    </ul>
  </body>
</html>

Этот код отлично работает в Chrome (43.0.2357.81), но не работает в Firefox (38.0.1 и 40.0a2) и Safari (8.0.6). В FF и Safari <style> просто добавляется к обычному DOM.

введите здесь описание изображения


person Eschon    schedule 02.06.2015    source источник


Ответы (1)


Репозиторий GitHub

octocatЯ разместил этот и другие фрагменты на github. Не стесняйтесь раскошелиться и улучшить.


Проблема в том, что webcomponets.js не «исправляет» стиль, который будет использоваться в браузерах, в которых отсутствует встроенная поддержка ShadowDOM. То есть браузер не может понимать такие селекторы, как :host.

Polymer решает эту проблему, переписывая стиль.

Итак, в разделе «Полимер» это:

:host ::content div

Становится так:

x-foo div

Поэтому, чтобы иметь это под компонентом VanillaJS, необходимо сделать это вручную.

Вот фрагмент, который я использую для создания Shadow Root и переписывания стилей только в браузерах, использующих webcomponents.js вместо родного Shadow DOM:

var addShadowRoot = (function () {
  'use strict';
  var importDoc, shimStyle;

  importDoc = (document._currentScript || document.currentScript).ownerDocument;

  if (window.ShadowDOMPolyfill) {
    shimStyle = document.createElement('style');
    document.head.insertBefore(shimStyle, document.head.firstChild);
  }

  return function (obj, idTemplate, tagName) {
    var template, list;

    obj.root = obj.createShadowRoot();
    template = importDoc.getElementById(idTemplate);
    obj.root.appendChild(template.content.cloneNode(true));

    if (window.ShadowDOMPolyfill) {
      list = obj.root.getElementsByTagName('style');
      Array.prototype.forEach.call(list, function (style) {
        if (!template.shimmed) {
          shimStyle.innerHTML += style.innerHTML
            .replace(/:host\b/gm, tagName || idTemplate)
            .replace(/::shadow\b/gm, ' ')
            .replace(/::content\b/gm, ' ');
        }
        style.parentNode.removeChild(style);
      });
      template.shimmed = true;
    }
  };
}());

Скопируйте и вставьте это в свой компонент.

Затем вам нужно вызвать эту функцию внутри вашего createdCallback, например:

addShadowRoot(this, "im-list-temp", "ul[is=im-list]");

Вот пример вашего кода

person chris-l    schedule 25.06.2015
comment
Это работает, поэтому я принял ответ, но решение, к которому я пришел, заключалось в переходе на полимер. - person Eschon; 26.06.2015