Как я могу клонировать ShadowRoot?

Я пытаюсь клонировать теневой корень, чтобы я мог поменять экземпляры <content></content> на соответствующие распределенные узлы.

Мой подход:

var shadowHost = document.createElement('div');
var shadowRoot = shadowHost.createShadowRoot();

var clonedShadowRoot = shadowRoot.cloneNode(true);

не работает, так как "узлы ShadowRoot не являются клонируемыми."

Мотивация для этого состоит в том, что я хочу получить составленное дерево теней, чтобы я мог использовать визуализированную разметку HTML.

Это может не работать из-за природы Shadow DOM, ссылка на распределенные узлы, вероятно, будет нарушена процессом клонирования.

Составление теневого дерева, вероятно, является встроенной функцией, но, просмотрев спецификацию w3c, я не смог найти такой метод.

Есть ли такой нативный метод? Или, если это не удастся, сработает ли ручной обход (копирование дерева в процессе)?

Ответ 1

ХОРОШО. Это немного сумасшествие, но я написал подпрограмму, которая клонирует детей shadowRoot. Это соответствует спецификации V1.

function cloneShadow(shadow) {
  const frag = document.createDocumentFragment();

  var nodes = [...shadow.childNodes];
  nodes.forEach(
    node => {
      node.remove();
      frag.appendChild(node.cloneNode(true));
      shadow.appendChild(node);
    }
  );

  return frag;
}

const s1 = document.querySelector('.shadow1');
const s2 = document.querySelector('.shadow2');

s1.attachShadow({mode:'open'}).innerHTML = '<h1>Header</h1>
<p>Content in a paragraph</p><slot></slot>';

setTimeout(() => {
  s2.attachShadow({mode:'open'}).appendChild(cloneShadow(s1.shadowRoot));}, 1000);
.shadow1 {
  background-color: #F88;
}

.shadow2 {
  background-color: #88F;
}
<div class="shadow1">
  <p>SHADOW 1</p>
</div>
<div class="shadow2">
  <p>SHADOW 2</p>
</div>

Ответ 2

Возможно, есть что-то большее, чего вы пытаетесь достичь, но кажется, что одним из способов обойти невозможность использования cloneNode является создание зеркального ShadowRoot а затем "клонирование" innerHTML из оригинала. Например:

const shadowRoot = document.createElement('div').attachShadow({mode: 'open'});
shadowRoot.appendChild(document.createElement('p'));
console.log('Original shadow tree', shadowRoot.childNodes);

const cloneRoot = document.createElement('div').attachShadow({mode: 'open'});
cloneRoot.innerHTML = shadowRoot.innerHTML;
console.log('Cloned shadow tree', cloneRoot.childNodes);