首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >多个后代选择器,bug或误解?

多个后代选择器,bug或误解?
EN

Stack Overflow用户
提问于 2021-04-11 18:40:25
回答 2查看 74关注 0票数 5

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

代码语言:javascript
复制
let tmp = fruits.querySelector("ul:first-of-type li:first-of-type");
tmp = tmp.querySelector("span")    

代码语言:javascript
复制
let tmp = fruits.querySelector("ul:first-of-type li:first-of-type span");

(在操作here中查看它)

我已经在火狐和chrome上测试过了。两种情况下的结果不同。有谁能解释一下原因吗?

堆栈代码片段中的示例:

代码语言:javascript
复制
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"))
代码语言:javascript
复制
<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>

EN

回答 2

Stack Overflow用户

发布于 2021-04-11 19:03:25

documentation对此进行了解释:

元素=baseElement.querySelector(选择器);

返回值

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

(重点是我的。)

让我们来看一个简化的例子:

代码语言:javascript
复制
console.log(document.getElementById("a").querySelector("ul li span"));
代码语言:javascript
复制
<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>,而且它们都在baseElement中。<span>A</span>恰好是这个集合中的第一个。

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

代码语言:javascript
复制
console.log(document.getElementById("a").querySelector(":scope ul li span"));
代码语言:javascript
复制
<ul>
  <li id="a"><span>A</span>
    <ul>
      <li><span>B</span></li>
    </ul>
  </li>
</ul>

票数 2
EN

Stack Overflow用户

发布于 2021-04-11 19:03:54

如果你不知道el.querySelector(selector)在后台是如何工作的,它可能会返回令人惊讶的结果。

代码语言:javascript
复制
 el.querySelector(selector)

实际情况是这样的:

代码语言:javascript
复制
 (el, selector) => [...document.querySelectorAll(selector)].filter(node => el !== node && el.contains(node))[0]

请参阅此示例:

代码语言:javascript
复制
const el = document.getElementById('outer');
const selector = 'span > span';
console.log(el.querySelector(selector).id); // logs "inner", not "innermost"
// same as if you did
console.log([...document.querySelectorAll(selector)].filter(node => el !== node && el.contains(node))[0].id);
代码语言:javascript
复制
<span id="outermost">
  <span id="outer">
    <span id="inner">
      <span id="innermost"></span>
    </span>
  </span>
</span>

因此,如果执行了document.querySelectorAll(selector)el.querySelector(selector)将返回中的第一个匹配项,该匹配项满足以下条件:找到的节点必须是el的后代。

更令人惊讶的是,如果您传递的selector没有匹配项,el.querySelector甚至会找到一个匹配项,因为selector的某些部分甚至不在el

代码语言:javascript
复制
const el = document.getElementById('outer');
const selector = '#outermost > span > span';
console.log(el.querySelector(selector).id); // logs "inner"!
// same as if you did
console.log([...document.querySelectorAll(selector)].filter(node => el !== node && el.contains(node))[0].id);
代码语言:javascript
复制
<span id="outermost">
  <span id="outer">
    <span id="inner">
      <span id="innermost"></span>
    </span>
  </span>
</span>

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67043990

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档