2017-06-12 83 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

相关问题