queryselectorAll,后代没有正确选择

时间:2018-03-28 22:35:13

标签: javascript dom selectors-api

我有以下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开始使用类test。我将它放在parent变量中,然后使用querySelectorAll尝试仅获取下一个列表中的a标记。但是,返回的节点列表还包括第一个a标记,即使它不是后代。这是我的代码:

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

真正奇怪的是,如果我只查询li后代,我只得到3.所以我不明白为什么当我查询那个li的子后代时我也得到了第一个a标记是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时,它正确地被设置为litest。我不明白为什么然后如果我从那里运行查询它仍然包含第一个a标记。正如我之前所说,如果我只查询ul > li,它会为我提供正确的li代码。

3 个答案:

答案 0 :(得分:3)

这是因为您尝试忽略的第一个<a>标记仍然属于选择器规则ul > li > a。因此,即使您以<li class="test">作为根开始查询(顺便说一下,我也不知道为什么其他答案说文档仍然是根),第一个孩子它找到的元素是<a>标记,实际上,它是<li>的子节点,它是<ul>的子节点。事实上,这种情况已经过去了......#34;您的指定根目录将被忽略。

修改 如果您希望将选择器规则限定为根,则可以使用此选项:

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

进一步澄清,browser CSS engines evaluate CSS rules right-to-left。在您看来,您希望浏览器从根(父<li class="test">)开始,然后找到<ul>标记,然后找到<li>标记,然后找到{{1} } 标签。

但是,浏览器以root身份启动,但随后查找根目录下的所有<a>标记。然后,它会检查<a>标记是否在<a>范围内,然后检查<li>是否在<li>范围内。所以<ul>标签确实是根,但它不遵循选择器规则的从左到右的层次结构,之后是从右到左。

答案 1 :(得分:1)

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

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

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

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>

答案 2 :(得分:0)

使用此选项定义var navChild = document.querySelectorAll("test > ul > li > a");。我不得不使用一个运行的例子来解决这个问题。这将获得您想要的3个香草<a>

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>