CSS选择器排除任何级别的任何父级都有类的所有子级 [英] CSS selector to exclude all children where any parent at ANY LEVEL has a class

查看:445
本文介绍了CSS选择器排除任何级别的任何父级都有类的所有子级的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



我试图创建一个CSS选择器来选择给定父代中的所有子代;但只要路径上的任何元素具有某个类别,就排除它们。

上下文

我在Javascript中创建了一些materialization类,它将一些元素替换为它们的材质版本。这运行在顶级应用程序上。每个用户都可以创建自己的应用程序,并且我希望能够说一定数量的元素不应该经过这个过程。

示例
$ b


$ b 应该选择:

 < div> 
< input />
< / div>

不应选择:

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

主要挑战是这个标签可以放在任何地方。示例:

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

或者它可以是:

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

已经过测试

我尝试了一些尝试。最好的情况是:

  div:not(.no-material)>输入:不是(.no-material),div:不是(.no-material)*:不是(.no-material)输入:不是(.no-material)
pre>

但是,它仍然带来一些误报。我可以通过添加很多级别来获得更准确的结果:

  div:not(.no-material)>输入:not(.no-material),
div:not(.no-material)> *:not(.no-material)>输入:not(.no-material),
div:not(.no-material)> *:not(.no-material)> *:not(.no-material)>输入:不是(.no-material)

像20-50个级别(或更多? ),但这并不是很聪明。



直播版

您可以测试您的选择器通过编辑Javascript中的cssSelector。


$ b

= {// Independent选择器'div:not(.no-material)>输入:not(.no-material)','div:not(.no-material)*:not(.no-material)input:not(.no-material)']。join(','); / /这将获得元素并运行他们的名字。我们应该得到yes1-5,但不是no1-5.let inputs = document.querySelectorAll(cssSelector); for(让输入输入)console.log(input.getAttribute('name')); <! -

<! - 不要编辑HTML,只需CSS选择器 - > < main style =display:none;> <! - 不可选 - > < div class =no-material> <输入名称=no-1> < / DIV> < DIV> < input name =no-2class =no-material> < / DIV> < DIV> < label class =no-material> <输入名称=no-3> < /标签> < / DIV> < DIV> < label class =no-material> <跨度> < input name =no-4> < /跨度> < /标签> < / DIV> < DIV> <标签> < span class =no-material> < input name =no-5> < /跨度> < /标签> < / DIV> <! - 可选 - > < DIV> < input name =yes-1> < / DIV> < DIV> < input name =yes-2> < / DIV> < DIV> <标签> < input name =yes-3> < /标签> < / DIV> < DIV> <标签> <跨度> <输入名称=是-4> < /跨度> < /标签> < / DIV> < DIV> <标签> <跨度> < input name =yes-5> < /跨度> < /标签> < / div>< / main><! - 不要编辑HTML,只是CSS选择器 - >



注意:我已经想到了解决这个问题的其他方法,比如迭代名为'.no-material'的元素的所有子元素,如果可能的话,将'no-material'添加到所有类中,但是这是耗费资源的问题,我想从CSS选择器的角度解决这个问题。

谢谢

解决方案

找到所有元素( all ),然后使用 no-material 对元素或其父元素( no ),然后从第一个元素中删除那些元素以找到那些元素()。



  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;> <! - 不可选 - > < div class =no-material> <输入名称=no-1> < / DIV> < DIV> < input name =no-2class =no-material> < / DIV> < DIV> < label class =no-material> <输入名称=no-3> < /标签> < / DIV> < DIV> < label class =no-material> <跨度> < input name =no-4> < /跨度> < /标签> < / DIV> < DIV> <标签> < span class =no-material> < input name =no-5> < /跨度> < /标签> < / DIV> <! - 可选 - > < DIV> < input name =yes-1> < / DIV> < DIV> < input name =yes-2> < / DIV> < DIV> <标签> < input name =yes-3> < /标签> < / DIV> < DIV> <标签> <跨度> <输入名称=是-4> < /跨度> < /标签> < / DIV> < DIV> <标签> <跨度> < input name =yes-5> < /跨度> < /标签> < / div>< / main>  

What

I am trying to create a CSS selector which selects all children within a given parent; but excludes them as long as any element on the path has a certain class.

Context

I am creating some materialisation class in Javascript which replaces some elements into their material versions. This runs on a top-level app. Each user can create their own apps, and I want to be able to say that a certain group of elements should not go through this process.

Example

This should be selected:

<div>
  <input />
</div>

This should not be selected:

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

The main challenge is that this label can be at any place. Example:

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

Or it could be:

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

Already tested

I tried a few attempts. The best scenario was:

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

However, it stills gives some false positives. I could get more accurate by adding a lot of levels like:

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)

And like that for 20-50 levels (or more?), but that's not very smart.

Live version

You can test your selectors by editing cssSelector in Javascript.

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

Note: I already have thought of other ways of solving this like iterating all the children of an element called '.no-material' and add the class 'no-material' to all, but that is resource consuming and I want to solve this from a CSS selector standpoint if possible.

Thank you

解决方案

Find all the elements (all), then the elements with no-material on the element or its parent (no), then remove those in the second from those in the first to find those that remain (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>

这篇关于CSS选择器排除任何级别的任何父级都有类的所有子级的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆