2017-06-12 58 views
1

什麼CSS選擇器來排除所有的孩子在那裏在任何級別的任何父母有一類

我想創建一個CSS選擇器,其選擇定父之內的所有兒童;但只要路徑上的任何元素具有某個類別就排除它們。

語境

我創建在Javascript中一些物質化類,它取代了一些元素融入到他們的物質形式。這運行在頂級應用程序上。每個用戶都可以創建自己的應用程序,並且我希望能夠說一定數量的元素不應該經歷這個過程。

這應選擇:

<div> 
    <input /> 
</div> 

這不應該被選擇:

<div class="no-material"> 
    <input /> 
</div> 

的主要挑戰是,這種標記可以是在任何地方。例如:

<main> 
    <section class="no-material"> 
     <form> 
     <fieldset> 
      <input /> 
     </fieldset> 
     </form> 
    </section> 
    </main> 

或者它可能是:

<main> 
    <section> 
     <form class="no-material"> 
     <fieldset> 
      <input /> 
     </fieldset> 
     </form> 
    </section> 
    </main> 

已經測試

我嘗試了一些嘗試。最好的情況是:

div:not(.no-material) > input:not(.no-material), div:not(.no-material) *:not(.no-material) input:not(.no-material) 

但是,它仍然給出了一些誤報。我可以通過添加很多的層次得到更準確的喜歡:

div:not(.no-material) > input:not(.no-material), 
div:not(.no-material) > *:not(.no-material) > input:not(.no-material), 
div:not(.no-material) > *:not(.no-material) > *:not(.no-material) > input:not(.no-material) 

而且像20-50的水平(或者更大),但是這不是很聰明。

真人版

您可以通過JavaScript編輯cssSelector測試你的選擇。

let cssSelector = [ 
 
    // Independent selectors 
 
    'div:not(.no-material) > input:not(.no-material)', 
 
    'div:not(.no-material) *:not(.no-material) input:not(.no-material)' 
 
].join(','); 
 

 
// This will get elements and run their names. We should get yes1-5, but not no1-5. 
 
let inputs = document.querySelectorAll(cssSelector); 
 
for (let input of inputs) console.log(input.getAttribute('name'));
<!-- Do not edit HTML, just the CSS selector --> 
 

 
<main style="display: none;"> 
 

 
    <!-- Not selectable --> 
 
    <div class="no-material"> 
 
    <input name="no-1"> 
 
    </div> 
 

 
    <div> 
 
    <input name="no-2" class="no-material"> 
 
    </div> 
 

 
    <div> 
 
    <label class="no-material"> 
 
     <input name="no-3"> 
 
    </label> 
 
    </div> 
 

 
    <div> 
 
    <label class="no-material"> 
 
     <span> 
 
     <input name="no-4"> 
 
     </span> 
 
    </label> 
 
    </div> 
 

 
    <div> 
 
    <label> 
 
     <span class="no-material"> 
 
     <input name="no-5"> 
 
     </span> 
 
    </label> 
 
    </div> 
 

 
    <!-- Selectable --> 
 
    <div> 
 
    <input name="yes-1"> 
 
    </div> 
 

 
    <div> 
 
    <input name="yes-2"> 
 
    </div> 
 

 
    <div> 
 
    <label> 
 
     <input name="yes-3"> 
 
    </label> 
 
    </div> 
 

 
    <div> 
 
    <label> 
 
     <span> 
 
     <input name="yes-4"> 
 
     </span> 
 
    </label> 
 
    </div> 
 

 
    <div> 
 
    <label> 
 
     <span> 
 
     <input name="yes-5"> 
 
     </span> 
 
    </label> 
 
    </div> 
 

 
</main> 
 
<!-- Do not edit HTML, just the CSS selector -->

注意:我已經想到了解決這個像迭代稱爲「沒有物質」元素的所有孩子的其他方式,並添加類的非物質',但這是資源消耗,我想從CSS選擇器的角度來解決這個問題。

謝謝

+0

不管,如果CSS選擇過程沒有任何索引(不知道的內部爲它的)無論如何,您最終都會以一種或另一種形式迭代所有元素。你可以通過一個'$(「[class]」)''選擇器(這是一個文字)迭代所有具有類的項目,然後如果他們有一個父類與你要過濾的類。 – Rogue

+0

對於初學者,當你想匹配任何級別的孩子時,不要使用'>'(直接孩子)。 – pawel

+0

這是一個解決的問題的重複:全局選擇符結合:not(.class)似乎並不工作https://stackoverflow.com/a/44497536/7973110 –

回答

1

查找所有元素(all),然後用no-material的元素或其父(no),然後刪除那些不同於第一第二,以找到那些仍然存在的元素( yes)。

const difference = (a, b) => a.filter(elt => b.indexOf(elt) === -1); 
 
    
 
const all = document.querySelectorAll("input"); 
 
const no = document.querySelectorAll(".no-material input, input.no-material"); 
 

 
const yes = difference([...all], [...no]); 
 

 
console.log(yes.map(elt => elt.name));
<main style="display: none;"> 
 

 
    <!-- Not selectable --> 
 
    <div class="no-material"> 
 
    <input name="no-1"> 
 
    </div> 
 

 
    <div> 
 
    <input name="no-2" class="no-material"> 
 
    </div> 
 

 
    <div> 
 
    <label class="no-material"> 
 
     <input name="no-3"> 
 
    </label> 
 
    </div> 
 

 
    <div> 
 
    <label class="no-material"> 
 
     <span> 
 
     <input name="no-4"> 
 
     </span> 
 
    </label> 
 
    </div> 
 

 
    <div> 
 
    <label> 
 
     <span class="no-material"> 
 
     <input name="no-5"> 
 
     </span> 
 
    </label> 
 
    </div> 
 

 
    <!-- Selectable --> 
 
    <div> 
 
    <input name="yes-1"> 
 
    </div> 
 

 
    <div> 
 
    <input name="yes-2"> 
 
    </div> 
 

 
    <div> 
 
    <label> 
 
     <input name="yes-3"> 
 
    </label> 
 
    </div> 
 

 
    <div> 
 
    <label> 
 
     <span> 
 
     <input name="yes-4"> 
 
     </span> 
 
    </label> 
 
    </div> 
 

 
    <div> 
 
    <label> 
 
     <span> 
 
     <input name="yes-5"> 
 
     </span> 
 
    </label> 
 
    </div> 
 

 
</main>

+0

這實際上是爲了Javascript;但我想解決它querySelectorAll級別,是的。我不明白你的情況如何解決這個問題。我試圖添加所有的輸入,除了那些父母(在任何級別)沒有任何材料的輸入,這是選擇父母擁有.no-material的輸入,這看起來微不足道,但是相反卻很難: ) – nitobuendia

+0

由於缺乏更好的答案,我將其標記爲答案。我採用了類似的方法,使用Set()和迭代器,但後面有相同的概念。 – nitobuendia

0

在現代瀏覽器中,你可以使用CSS變量。

在根級別定義它,它重新定義在類:

:root { 
 
    --mycolor: lightblue; 
 
} 
 

 
.container { 
 
    --mycolor: lightgreen; 
 
} 
 

 
.test { 
 
    background-color: var(--mycolor); 
 
}
<div class="test">BASE</div> 
 

 
<div class="container"> 
 
    <div class="test">BASE</div> 
 
</div>

+0

謝謝。這很好,但這不適用於此目的。在Javascript中使用CSS選擇器來將某些類和行爲應用於元素。 – nitobuendia

相關問題