首页 > 解决方案 > 多个后代选择器,错误或误解?

问题描述

以下两种选择节点的方法不应该产生相同的结果吗?

let tmp = fruits.querySelector("ul:first-of-type li:first-of-type");
tmp = tmp.querySelector("span")    

对比

let tmp = fruits.querySelector("ul:first-of-type li:first-of-type span");

(在此处查看实际操作)

我已经在 Firefox 和 chrome 中对此进行了测试。两种情况的结果不同。有人可以解释为什么吗?

堆栈片段中的示例:

let fruits = document.querySelector("[data-segment='fruits']");
console.log(fruits);
let tmp = fruits.querySelector("ul:first-of-type li:first-of-type")
tmp = tmp.querySelector("span")
console.log("Works:")
console.log(tmp)
console.log("Does not work:")
console.log(fruits.querySelector("ul:first-of-type li:first-of-type span"))
<main id="app" data-v-app="">
  <section>
    <h2>Tree</h2>
    <ul role="tree">
      <li role="treeitem" data-segment="fruits" aria-level="1" aria-setsize="3" aria-posinset="1" aria-expanded="true"><span tabindex="0">Fruits</span>
        <ul role="group">
          <li role="none" data-segment="oranges" aria-level="2" aria-setsize="5" aria-posinset="1"><span tabindex="-1">Oranges</span>
            <!--v-if-->
          </li>
          <li role="none" data-segment="pineapple" aria-level="2" aria-setsize="5" aria-posinset="2"><span tabindex="-1">Pineapple</span>
            <!--v-if-->
          </li>
          <li role="treeitem" data-segment="apples" aria-level="2" aria-setsize="5" aria-posinset="3" aria-expanded="false"><span tabindex="-1">Apples</span>
            <ul role="group">
              <li role="none" data-segment="macintosh" aria-level="3" aria-setsize="3" aria-posinset="1"><span tabindex="-1">Macintosh</span>
                <!--v-if-->
              </li>
              <li role="none" data-segment="granny_smith" aria-level="3" aria-setsize="3" aria-posinset="2"><span tabindex="-1">Granny Smith</span>
                <!--v-if-->
              </li>
              <li role="none" data-segment="fuji" aria-level="3" aria-setsize="3" aria-posinset="3"><span tabindex="-1">Fuji</span>
                <!--v-if-->
              </li>
            </ul>
          </li>
          <li role="none" data-segment="bananas" aria-level="2" aria-setsize="5" aria-posinset="4"><span tabindex="-1">Bananas</span>
            <!--v-if-->
          </li>
          <li role="none" data-segment="pears" aria-level="2" aria-setsize="5" aria-posinset="5"><span tabindex="-1">Pears</span>
            <!--v-if-->
          </li>
        </ul>
      </li>
      <li role="none" data-segment="vegetables" aria-level="1" aria-setsize="3" aria-posinset="2"><span tabindex="-1">Vegetables</span>
        <!--v-if-->
      </li>
      <li role="none" data-segment="grains" aria-level="1" aria-setsize="3" aria-posinset="3"><span tabindex="-1">Grains</span>
        <!--v-if-->
      </li>
    </ul>
  </section>
</main>

标签: javascriptcssqueryselector

解决方案


文档对此进行了解释:

element = baseElement.querySelector(selectors);

返回值

baseElement与指定组匹配的第一个后代元素selectors匹配时考虑元素的整个层次结构,包括元素集之外的元素,包括baseElement及其后代;换句话说,selectors首先应用于整个文档,而不是baseElement,以生成潜在元素的初始列表。然后检查生成的元素以查看它们是否是baseElement. 该querySelector方法返回那些剩余元素的第一个匹配项。

(强调我的。)

让我们考虑一个简化的例子:

console.log(document.getElementById("a").querySelector("ul li span"));
<ul>
  <li id="a"><span>A</span>
    <ul>
      <li><span>B</span></li>
    </ul>
  </li>
</ul>

这里,baseElementdocument.getElementById("a")selectors"ul li span"

document.querySelector("ul li span")确实包括两个<span>s,并且它们都在 inside baseElement<span>A</span>恰好是这个集合中的第一个。

有一个相当新的伪类:scope,在这里可能会有所帮助:

console.log(document.getElementById("a").querySelector(":scope ul li span"));
<ul>
  <li id="a"><span>A</span>
    <ul>
      <li><span>B</span></li>
    </ul>
  </li>
</ul>


推荐阅读