我们如何检测是否使用v0或v1 API创建了影子根?

时间:2016-10-12 16:47:36

标签: javascript html dom web-component shadow-dom

假设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".

更多信息:

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

2 个答案:

答案 0 :(得分:2)

我对Hayato Ito的答案采取了类似的方向。但是,我不是创建slot元素,而是定位content元素。我无法找到检测任何API方法检测版本的方法。

我定位了content个元素,因为内容元素本身并没有为它们设置事件,这与slotchange事件上的slot不同,这有望带来小的性能提升。如果浏览器根本不支持v1,该函数会更快地返回v0

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;
}

它肯定感觉像是一个“黑客”,因为需要附加随机dom :(。我在Chrome,Firefox,Safari,IE11和Edge中测试了这个。我测试了使用webcomponentsjs(v0)polyfill制作的组件,并且它为每个组件正确返回v0。我还使用shadydom(v1)polyfill测试了那些相同的浏览器,其中包含使用v1规范创建的组件,并在所有这些浏览器中收到v1

答案 1 :(得分:1)

以下黑客应该有效:

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,当你必须检测到它时,会出现问题。