【问题标题】:queryselectorAll with descendant not selecting correctly后代未正确选择的 queryselectorAll
【发布时间】:2018-09-07 18:33:13
【问题描述】:

我有以下 DOM 结构:

    var parent = document.querySelector(".test");
    var navChild = parent.querySelectorAll("ul > li > a");
    for (i = 0; i < navChild.length; i++) {
            navChild[i].style.backgroundColor = "red";
        }
    console.log(navChild.lenght);
    console.log(navChild);
<!-- begin snippet: js hide: false console: true babel: false -->
    <ul>
      <li class="test">
        <a>ssss</a> <!--this will also be affected -->
        <ul>
          <li><a>fsfsf</a></li>
          <li><a>sff</a></li>
          <li><a>ggg</a></li>
        </ul>
      </li>
    </ul>

我想使用 vanilla javascript 选择 3 个 a 标记,并从带有类测试的 li 开始。我把它放在一个parent 变量中,然后使用querySelectorAll 来尝试只获取下一个列表中的a 标记。但是,返回的节点列表还包括第一个 a 标记,即使它不是后代。这是我的代码:

var navChild = parent.querySelectorAll("ul > li > a");

真正奇怪的是,如果我只查询 li 后代,我只会得到 3。所以我不明白为什么当我查询 li 的子后代时,我也会得到第一个 @987654332 @ 标记在 DOM 上两级。

我知道我可以使用 jQuery 做到这一点,但我不想使用它。

已编辑以显示我如何设置父变量

我正在尝试将那些a 标签添加到childs 变量中,然后在我不想包含在子节点列表中的第一个a 标签上按下回车键.

var alinks = document.querySelectorAll('.test > a');
[].forEach.call(alinks, function(link){
    link.addEventListener('keyup', function(e){
        e.preventDefault();
        if(e.keyCode === 13) {
            var linkParent = e.target.parentElement;
            var childs = menuParent.querySelectorAll('ul > li > a');
        }        
    })
});

当我登录 linkParent 时,它被正确设置为 li 类 test。我不明白为什么如果我从那里运行查询,它仍然包含第一个 a 标记。正如我之前所说,如果我只查询ul &gt; li,它会给我正确的li 标签。

【问题讨论】:

标签: javascript dom selectors-api


【解决方案1】:

这是因为您尝试忽略的第一个 &lt;a&gt; 标记仍属于选择器规则 ul &gt; li &gt; a。因此,即使您以 &lt;li class="test"&gt; 作为根开始查询(顺便说一下,我不知道为什么其他答案说文档仍然是根),它找到的第一个子元素是&lt;a&gt; 标签,实际上,它是 &lt;li&gt; 的子代,&lt;ul&gt; 的子代。这最终会“超过”您指定的根的事实被忽略了。

编辑: 如果您希望选择器规则也适用于根,您可以使用它来代替:

parent.querySelectorAll(":scope ul > li > a");

为了进一步澄清,browser CSS engines evaluate CSS rules right-to-left。在您的想法中,您希望浏览器从根(父级&lt;li class="test"&gt;)开始,然后找到&lt;ul&gt; 标记,然后找到&lt;li&gt; 标记,然后找到&lt;a&gt; 标记。

但是,浏览器从根目录开始,然后查找根目录下的所有&lt;a&gt; 标记。然后它检查&lt;a&gt; 标记是否在&lt;li&gt; 内,然后检查&lt;li&gt; 是否在&lt;ul&gt; 内。所以&lt;li class="parent"&gt; 标记确实是根,但之后它不遵循选择器规则的从左到右的层次结构,而是从右到左。

【讨论】:

  • 所以你是说在运行这种类型的后代查询时,它总是忽略根,只找到符合选择器规则的项目??
  • @chavab_1 不,我不是这个意思。它只会找到符合选择器规则且位于根下方的项目——第一个 &lt;a&gt; 标记位于根下方。但是,它“忽略”的部分是 &lt;a&gt; 标记的父元素使其适合规则可以位于根之上。
  • @chavab_1 如果这不是您想要的行为,请参阅我关于添加:scope的编辑
  • 非常感谢。我不知道;我期待与在 CSS 中使用选择器规则时相同的行为。正如您所解释的,我在此链接中找到了确切的答案:developer.mozilla.org/en-US/docs/Web/API/Element/… 现在一切正常。再一次,谢谢!!
  • 我发现 IE(大惊喜)和 Opera 都不支持 :scope 伪类。你有另一种方法来解决这个任务吗?我可以忽略节点列表中的第一个节点,它会解决这个问题,但是我还必须确保我只选择直接后代的节点,因为每个子 as 也可以有一个 ul , li 和 as 自己的。我唯一能想到的就是使用children 方法,直到我到达我需要的节点。但我只是认为必须有更好的解决方案。
【解决方案2】:

这是因为您的第一个 &lt;a&gt; 也匹配 ul &gt; li &gt; a,并且由于说 a 仍然是调用元素 qSA 的后代,因此它被包含在 NodeList 中。

https://developer.mozilla.org/en-US/docs/Web/API/Element/querySelectorAll#Javascript

Element.querySelector 和 Element.querySelectorAll 在这方面有些古怪:虽然唯一匹配的元素必须是您调用它的 Element 的子元素,但选择器字符串 仍然从文档级别开始 -它不会通过首先隔离元素及其后代来验证选择器。

const child = document.querySelector('#child');
const span = child.querySelector('#parent span');
console.log(span.textContent);
<div id="parent">
<div id="child">
<span>text</span>
</div>
</div>

【讨论】:

  • 我认为这并不能真正回答问题。正在使用子选择器 (&gt;),因此它应该只返回作为 li 子元素的 a 元素,而这些元素又是 ul 元素的子元素。这更像是他使用ul &gt; li, li &gt; a
  • 他没想到会被选中的a是与ul &gt; li &gt; a匹配的a。
  • 我不会称之为“古怪”。它准确地选择了符合选择器描述的元素。他们可以使用:scope 来限制选择。 parent.querySelectorAll(":scope ul &gt; li &gt; a");
【解决方案3】:

使用它来定义您的var navChild = document.querySelectorAll("test &gt; ul &gt; li &gt; a");。我不得不使用一个正在运行的示例来解决这个问题。这将得到你想要的 3 vanilla &lt;a&gt;

querySelectorAll() 方法将文档中与指定 CSS 选择器匹配的所有元素作为静态 NodeList 对象返回。

我认为即使您在文档中设置了父级也是如此。

var navChild = document.querySelectorAll(".test > ul > li > a");
for (i = 0; i < navChild.length; i++) {
        navChild[i].style.backgroundColor = "red";
}
//console.log(navChild.lenght);
//console.log(navChild);
<ul>
  <li class="test">
    <a>qqqq</a>
    <ul>
      <li><a>aaa</a></li>
      <li><a>bbb</a></li>
      <li><a>ccc</a></li>
    </ul>
  </li>
</ul>

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-11-09
  • 1970-01-01
  • 2022-07-05
  • 2022-06-15
  • 1970-01-01
  • 2013-01-02
  • 1970-01-01
相关资源
最近更新 更多