2017-04-12 22 views
2

我試圖讓兩個給定的DOM節點共同抵消母公司之一,它完美的作品時,兩個節點都是裏面的文件,但它確實不是他們中的一個時在Shadow DOM中。使用getRange暗影DOM內的兩個元素

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

我怎樣才能讓暗影DOM createRange工作?

回答

1

不能定義一系列這樣的,因爲這兩個元素是在不同的節點樹。

根據the specification:沒有定義

選擇。實施應該盡最大努力爲他們做最好的事情。這裏是一個可能,固然幼稚的方式:

因爲它們是在不同的節點樹的節點永遠不會有相同的根,有可能永遠存在跨越多個節點樹的有效DOM範圍。

因此,選擇可以只在一個節點樹內的存在,因爲它們是由一個單一的範圍限定。由window.getSelection()方法返回的選擇決不會返回陰影樹內的選擇。陰影根對象的

的getSelection()方法返回在此陰影樹中的當前選擇。

因此,您應該定義2個範圍:一個在文檔DOM樹中,另一個在影子DOM樹中。

在你的函數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

至少現在我知道我的解決方案並不奇怪,因爲至少世界上的另一個人最終會得到同樣的東西,eheh。 –