我们如何检测影子根是用 v0 还是 v1 API 创建的?

How do we detect if a shadow root was made with v0 or v1 API?

假设一个 JS 模块导出 shadowRoot,它是使用 el.createShadowRootel.attachShadow(我们不知道是哪个)创建的。我们如何检测根是 v0 影子根还是 v1 影子根(即我们如何检测使用哪种方法创建根)?

f.e.,下面的条件语句填什么?

// for argument's sake, we don't create the root, we only get a reference
// to it:
import shadowRoot from 'somewhere'

function getShadowRootVersion(root) {
    if ( ... )
        return 'v0'

    if ( ... )
        return 'v1'
}

console.log(getShadowRootVersion(shadowRoot)) // should output "v0" or "v1".

更多信息:

我们想知道影子根是从 createShadowRoot 还是从 attachShadow 创建的。生成的根是不同的:在用 createShadowRoot 创建的根中, <content> 元素用于分配元素。在使用 attachShadow 创建的根中,<content> 元素不执行任何操作,而是使用 <slot> 元素。我们如何检测使用哪种方法创建根(即我们是否有 v0 根或 v1 根)?

以下 hack 应该有效:

function isV1(shadowRoot) {
  const slot = document.createElement('slot');
  shadowRoot.appendChild(slot);
  slot.appendChild(document.createElement('div'));
  const assignedNodes = slot.assignedNodes({ flatten: true });
  slot.remove();
  return assignedNodes.length !== 0;
}

IMO,一定要检测的时候出问题了

我的方向与伊藤隼人的回答相似。但是,我没有创建 slot 个元素,而是以 content 个元素为目标。我无法找到一种方法来检测任何 API 方法检测的版本。

我以 content 元素为目标,因为内容元素本身没有事件,这与 slot 事件上的 slotchange 不同,后者有望带来小幅性能提升。如果浏览器根本不支持 v0,加上函数 returns v1 会快一点。

function shadowType(shadowRoot) {
    if (!shadowRoot) {
        // closed shadow dom does not appear to have a shadowRoot...
        // It could be assumed that it is v1, but for now return undefined
        return;
    }

    const content = document.createElement('content');
    // In browsers that support v1, but not v0 (ex: Safari)
    if (!content.getDistributedNodes) {
        return 'v1';
    }

    content.setAttribute('select', 'test-shadow-dom-version');
    shadowRoot.appendChild(content);

    const testElement = document.createElement('test-shadow-dom-version');
    shadowRoot.host.appendChild(testElement);
    const type = (content.getDistributedNodes().length) ? 'v0' : 'v1';
    shadowRoot.removeChild(content);
    shadowRoot.host.removeChild(testElement);

    return type;
}

感觉确实像 "hack",因为需要附加 运行dom dom :(。我在 Chrome 中测试过这个, Firefox、Safari、IE11 和 Edge。我测试了使用 webcomponentsjs (v0) polyfill 制作的组件,它为每个组件正确返回了 v0。我还测试了那些相同的浏览器,仅使用 shadydom ( v1) 使用 v1 规范创建的组件进行 polyfill,并在所有这些浏览器中收到 v1