2014-03-01 155 views
91

如何找到與具有特定類別的樹木最接近的元素的祖先,純JavaScript中的?例如,像這樣一棵樹:查找具有特定類別的最接近的祖先元素

<div class="far ancestor"> 
    <div class="near ancestor"> 
     <p>Where am I?</p> 
    </div> 
</div> 

然後我想div.near.ancestor如果我嘗試這對p和搜索ancestor

+0

請注意,外部div不是父親,它是'p'元素的*祖先*。如果你實際上只想獲得父節點,你可以執行'ele.parentNode'。 –

+0

@FelixKling:不知道那個術語;我會改變它。 – rvighne

+2

它實際上與我們人類使用的一樣:)您父親(父母)的父親(父母)不是您的父親(父母),而是您的祖父(祖父母),或者更一般地說,您的祖先。 –

回答

141

該做的伎倆:

function findAncestor (el, cls) { 
    while ((el = el.parentElement) && !el.classList.contains(cls)); 
    return el; 
} 

while循環等待,直到el具有所需的類,並將其設置elel的父母每次迭代所以在最後,你有這個類的祖先或null

Here's a fiddle,如果有人想改善它。它不適用於舊瀏覽器(即IE);看到這個compatibility table for classListparentElement在這裏使用,因爲parentNode將涉及更多的工作,以確保該節點是一個元素。

+1

有關'.classList'的替代方法,請參閱http://stackoverflow.com/q/5898656/218196。 –

+1

我修正了代碼,但如果沒有這樣的類名的祖先,它仍會拋出錯誤。 –

+0

@FelixKling:你能解釋爲什麼'parentElement'錯了嗎? – rvighne

131

更新:現在支持in most major browsers

document.querySelector("p").closest(".near.ancestor") 

注意,這可以匹配選擇,而不僅僅是類

https://developer.mozilla.org/en-US/docs/Web/API/Element.closest


對於不支持closest()但有matches()一個傳統的瀏覽器可以構建類似於@ rvighne的類匹配的選擇器匹配:

function findAncestor (el, sel) { 
    while ((el = el.parentElement) && !((el.matches || el.matchesSelector).call(el,sel))); 
    return el; 
} 
+7

謝謝,隨着瀏覽器追上,這將是幾個月內的最佳答案。 – rvighne

+1

當前版本的Internet Explorer,Edge和Opera Mini仍然不支持。 – kleinfreund

+1

@kleinfreund - 在IE,Edge或Opera mini中仍然不支持。 http://caniuse.com/#search=closest – evolutionxbox

6

基礎上the8472 answerhttps://developer.mozilla.org/pl/docs/Web/API/Element/matches這裏是跨平臺的解決方案2017年:

if (!Element.prototype.matches) { 
    Element.prototype.matches = 
     Element.prototype.matchesSelector || 
     Element.prototype.mozMatchesSelector || 
     Element.prototype.msMatchesSelector || 
     Element.prototype.oMatchesSelector || 
     Element.prototype.webkitMatchesSelector || 
     function(s) { 
      var matches = (this.document || this.ownerDocument).querySelectorAll(s), 
       i = matches.length; 
      while (--i >= 0 && matches.item(i) !== this) {} 
      return i > -1; 
     }; 
} 

function findAncestor(el, sel) { 
    if (typeof el.closest === 'function') { 
     return el.closest(sel) || null; 
    } 
    while (el) { 
     if (el.matches(sel)) { 
      return el; 
     } 
     el = el.parentElement; 
    } 
    return null; 
} 
+0

簡單而美麗 – Michael

7

@rvighne液效果很好,但在意見中指明ParentElementClassList都有兼容性問題。爲了使它更兼容,我用:

function findAncestor (el, cls) { 
    while ((el = el.parentNode) && el.className.indexOf(cls) < 0); 
    return el; 
} 
  • parentNode屬性,而不是在className屬性,而不是對classList屬性contains方法parentElement財產
  • indexOf方法。

當然,indexOf只是查找該字符串的存在,它並不關心它是否是整個字符串。所以,如果你有另一個類'祖先類型'的元素,它仍然會返回找到'祖先',如果這對你來說是一個問題,也許你可以使用正則表達式來找到一個完全匹配。

相關問題