2017-06-18 49 views
0

(請不要JQUERY) 假設我有以下樹。我想迭代從div.foo開始匹配querySelectorAll('div.bar')的元素,但不會覆蓋與相同選擇器匹配的子元素。我怎麼做?DOM:遍歷元素,排除與匹配相同的選擇器的嵌套元素

div.foo 
    div.bar -- select 
    div.bar -- select 
    div.bar -- skip 
    div.bar -- skip 
    div.damnSon 
    div.bar -- select 
    div.bar -- select 
     div.bar --skip 
    div.bar -- select 
    div.bar -- skip 

TreeWalker是,一個沒有去,因爲

  • 它完全拒絕該元素,而我仍然要處理它,只是沒有它的孩子
  • 它只能在可見的元素,而我可能正在迭代隱藏的項目 NodeIterator由於相同的問題而無法工作,並且即使在拒絕父項時也會對子項進行迭代。

最理想的情況是以某種方式得到querySelector的結果不平坦。然後我只需循環它們而不必關心自己的嵌套屬性。

+0

遍歷並檢查類是在父鏈元素... –

+0

@Jonasw這是行不通的。首先,您要求在每個單個匹配元素上對樹進行子迭代,以查看它是否可能包含父級,然後在調用parent.containsNode時進行另一次迭代。其次,如果我從具有相同選擇器的根元素中調用此元素,除非我明確地停止根元素上的循環,否則所有元素都不會通過檢查,這會使其效率更低。 – Megakoresh

+0

由於不存在「父選擇器」,並且因爲':not()'僅使用簡單的選擇器,並且不適合表示「if(not)」,所以我看不到純CSS選擇器在「更復雜樹木中的星座。 //你能詳細談談你最終想要對這些元素做什麼?在我看來,你自我回答現在指出的三個問題中的兩個本應該已經被制定爲對問題本身的限制。那麼「還有什麼」......? – CBroe

回答

0

到目前爲止,我想出了以下酒精方法:

let nodeIterator = document.createNodeIterator(root, NodeFilter.SHOW_ELEMENT); 
let node; 
while(node = nodeIterator.nextNode()){ 
    if (node.matches('.bar .bar')) { 
    //skip 
    } else if (node.matches('.bar')) { 
    //do things 
    } 
} 

這樣做的問題是:

  • 它的速度慢 - 特別是在SVGs或任何有很多元素
  • 它仍然是平坦的。
  • 它會破壞如果div.foo(即我的根元素)本身嵌套內側(div.bar

如果任何人都可以建議更好的方法,這會是十分讚賞。


UPDATE: 好了,所以我想出了下面的方法,排序,解決了最後一點,而不在於更加低效:

let bars = root.getElementsByClassName('bar'); 
let excludedChildren = []; 
for(let i = 0; i < bars.length; i++){ 
    let children = bars[i].getElementsByClassName('bar'); 
    if(children.length>0) Array.prototype.push.apply(excludedChildren, children); 
} 
bars = bars.filter(e=>!excludedChildren.includes(e)); 
bars.forEach(e=>{ 
    //do stuff 
}); 

UPDATE: 時間關閉這老sh * t了,here is my final solution。現在在生產中已經工作了一個月,沒有任何問題。當然這不能處理一些非常複雜的情況,但它是可擴展的。

0
var elems=Array.prototype.filter.call(querySelectorAll('div.bar'),function(el){ 
    var foochild=false; 
    while(el=el.parent){ 
    if(el.classList.contains("bar") return false;//fail as its a div.bar children 
    if(el.classList.contains("foo")) foochild=true;//were a children of foo 
    } 
    return foochild; 
}); 

只需在dom樹中篩選關於其父母的div.bars。


另一種方式是通過所有直接foo的孩子的被迭代:

Array.prototype.forEach.call(document.querySelectorAll("div.foo"),function iterate(foo){ 
    for(var i=0;i<foo.children.length){ 
    var child=foo.children[i]; 
    if(child.classList.contains("bar")){ 
    //weve found a bar 
    }else{ 
    iterate(child);//find subbars 
    } 
    } 
}); 
+0

這比我的解決方案還要慢,如果'div.foo'(即我的根)本身嵌套在'div.bar'中,它將不起作用。 – Megakoresh

+0

其實我現在也不會想到這件事。需要將其添加到答案中。 – Megakoresh

+0

@megakoresh可以使工作。 –

相關問題