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

旧城冷巷雨未停 提交于 2019-12-02 01:31:59

问题


Suppose a JS module exports shadowRoot which was created with either el.createShadowRoot or el.attachShadow (we don't know which). How do we detect if the root is a v0 shadow root or a v1 shadow root (i.e. how do we detect which method was used to create the root)?

f.e., What would I fill in the following conditional statements?

// 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".

More info:

We want to find out if a shadow root was created from createShadowRoot or from attachShadow. The resulting roots are different: in the root created with createShadowRoot, <content> elements are used for distributing elements. In roots created with attachShadow, <content> elements don't do anything, and <slot> elements are used instead. How do we detect which method was used to create a root (i.e. whether we have a v0 root or a v1 root)?


回答1:


I went a similar direction to Hayato Ito's answer. However, instead of creating slot elements, I target content elements. I was not able to find a way to detect the version off of any API method detection.

I targeted content elements since content elements do not natively have events for them, unlike slotchange on the slot event, which hopefully could lead to a small performance boost. Plus the function returns v1 a little faster if the browser does not support v0 at all.

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

It definitely feels like a "hack", because of need to append random dom :(. I did test this in Chrome, Firefox, Safari, IE11, and Edge. I tested components made using the webcomponentsjs (v0) polyfill, and it correctly returned v0 for each component. I also tested those same browsers with just the shadydom (v1) polyfill with components created with the v1 spec, and received v1 in all of those browsers.




回答2:


The following hack should work:

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, there is something wrong when you have to detect it.



来源:https://stackoverflow.com/questions/40004064/how-do-we-detect-if-a-shadow-root-was-made-with-v0-or-v1-api

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!