2017-04-12 6 views
2

2つのDOMノードの共通のオフセット親を取得しようとしていますが、両方のノードがドキュメント内にあるときに問題なく動作しますが、影のDOMにあります。私はシャドウDOMとcreateRange作業を行うことができますどのようにShadow DOM内の2つの要素のうちの1つとgetRangeを使用

function isOffsetContainer(element) { 
 
    return element.firstElementChild.offsetParent === element 
 
} 
 

 

 
function findCommonOffsetParent(element1, element2) { 
 
    const range = document.createRange(); 
 
    if (element1.compareDocumentPosition(element2) & Node.DOCUMENT_POSITION_FOLLOWING) { 
 
     range.setStart(element1, 0); 
 
     range.setEnd(element2, 0); 
 
    } else { 
 
     range.setStart(element2, 0); 
 
     range.setEnd(element1, 0); 
 
    } 
 

 
    const { commonAncestorContainer } = range; 
 
    
 
    // When one of the two elements is inside Shadow DOM, the `commonAncestorContainer` 
 
    // returned is actually one of the two given elements in the range... 
 
    // For demo purposes, we detect this situation and we `console.log` it 
 
    if ([element1, element2].includes(commonAncestorContainer)) { 
 
     console.log('Shadow DOM '); 
 
    } else { 
 
     if (isOffsetContainer(commonAncestorContainer)) { 
 
      return commonAncestorContainer; 
 
     } 
 

 
     const offsetParent = commonAncestorContainer && commonAncestorContainer.offsetParent; 
 

 
     if (!offsetParent || offsetParent && offsetParent.nodeName === 'BODY') { 
 
      return window.document.documentElement; 
 
     } 
 

 
     return offsetParent; 
 
    } 
 
} 
 

 

 
// Demo code 
 
const reference = document.createElement('div'); 
 
reference.className = 'reference'; 
 
reference.innerText = 'reference'; 
 

 
const shadowParent = document.createElement('div'); 
 
document.body.appendChild(shadowParent); 
 
document.body.appendChild(reference); 
 
const shadow = shadowParent.createShadowRoot(); 
 
document.body.appendChild(shadow); 
 

 
const popper = document.createElement('div'); 
 
popper.className = 'popper'; 
 
popper.innerText = 'popper'; 
 
shadow.appendChild(popper); 
 

 
findCommonOffsetParent(popper, reference);
.popper { 
 
    width: 100px; 
 
    height: 100px; 
 
    background: red; 
 
} 
 

 
.reference { 
 
    width: 100px; 
 
    height: 100px; 
 
    background: blue; 
 
}

答えて

1

2つの要素が異なるノードツリーにあるため、このような範囲を定義することはできません。 the specificationによると

選択が定義されていません。実装は、それらのために最善を尽くすために最善を尽くすべきです。

異なるノードツリーにあるノードは決して同じルートを持たないので、複数のノードツリーにまたがる有効なDOM範囲が存在しないことがあります。

したがって、選択は単一の範囲で定義されるため、1つのノードツリー内にのみ存在することがあります。 window.getSelection()メソッドによって返された選択は、決してシャドウツリー内の選択を返しません。

シャドウ・ルート・オブジェクトのgetSelection()メソッドは、このシャドウ・ツリー内の現在の選択を戻します。

結果として、ドキュメントDOMツリーとシャドウDOMツリーの2つの範囲を定義する必要があります。あなたの関数findCommonOffsetParent()の開始時に

、あなたは要素がシャドウDOMやないgetRootNode()を使用しているかどうかをテストするために開始すべきこと:あなたのユースケースに応じて、あなたが入れ子になっている可能性があること

if (element1.getRootNode().host) 
    //in a shadow DOM 
else 
    //in the main document 

注意シャドーDOMを再帰的に検索する必要があります。

しかし、いくつかの単純な状況(例のような)では、2つの範囲を扱うのはかなり簡単です。

共通の祖先を取得するには:

var shadow_host1 = element1.getRootNode().host 
var shadow_host2 = element2.getRootNode().host 

if (shadow_host1) element1 = shadow_host1 
if (shadow_host2) element2 = shadow_host2 

//create range... 
+0

が、私は同様のソリューションhttps://github.com/FezVrasta/popper.js/pull/201/files#diff-3841f93aefe44e3ce876c730b18768d7R22 –

+0

になってしまった、ありがとうあなたは私よりも速かった! – Supersharp

+1

少なくとも私の解決策は奇妙なことではないことは分かっています。なぜなら、少なくとも世界の他の人は同じことで終わったからです。 –

関連する問題