带有后代的 queryselectorAll 没有正确选择
queryselectorAll with descendant not selecting correctly
我有以下 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>
我想 select 3 a
标签使用原版 javascript 并从 li
开始使用 class 测试。我将它放在 parent
变量中,然后使用 querySelectorAll 尝试仅获取下一个列表中的 a
标签。但是,返回的节点列表还包括第一个 a
标记,即使它不是后代。这是我的代码:
var navChild = parent.querySelectorAll("ul > li > a");
真正奇怪的是,如果我只查询 li
个后代,我只会得到 3 个。所以我不明白为什么当我查询那个 li
的子后代时,我也得到第一个 a
标签,它比 DOM.
高两层
我知道我可以使用 jQuery 来做到这一点,但我不想使用它。
已编辑以显示我如何设置父变量
我尝试在第一个 a
标签上按下回车键后将那些 a
标签添加到 childs
变量想要包含在子节点列表中。
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
和 class test
。我不明白为什么如果我从那里 运行 查询它仍然包含第一个 a
标记。正如我之前所说,如果我只查询 ul > li
它会给我正确的 li
标签。
这是因为您的第一个 <a>
也匹配 ul > li > a
,并且由于所说的 a
仍然是调用元素 qSA 的后代,它被包含在 NodeList 中。
https://developer.mozilla.org/en-US/docs/Web/API/Element/querySelectorAll#Javascript
Element.querySelector 和 Element.querySelector 在这方面都有些古怪:虽然唯一匹配的元素必须是您调用它的元素的子元素,但选择器字符串 仍然开始在文档级别 - 它不会首先通过隔离元素及其后代来验证选择器。
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>
这是因为您试图忽略的第一个 <a>
标记仍然属于选择器规则 ul > li > a
。因此,即使您以 <li class="test">
作为根开始查询(顺便说一句,我不知道为什么其他答案说文档仍然是根),第一个子元素它finds 是 <a>
标签,实际上,它是 <li>
的子标签,而 <li>
是 <ul>
的子标签。事实上,这最终会 "above" 您指定的根被忽略。
编辑:
如果您也希望选择器规则的范围限定为根目录,则可以改用它:
parent.querySelectorAll(":scope ul > li > a");
为了进一步说明,browser CSS engines evaluate CSS rules right-to-left。在您看来,您希望浏览器从根目录(父 <li class="test">
)开始,然后找到一个 <ul>
标签,然后找到一个 <li>
标签,然后找到一个 <a>
标签。
但是,浏览器从根目录开始,然后查找根目录下的所有 <a>
标签。然后它检查 <a>
标签是否在 <li>
内,然后检查 <li>
是否在 <ul>
内。所以 <li class="parent">
标签确实是根,但之后它不遵循选择器规则的 left-to-right 层次结构,而是 right-to-left.
使用它来定义您的 var navChild = document.querySelectorAll("test > ul > li > a");
。我不得不使用 运行 示例来解决问题。这将得到你想要的 3 个香草 <a>
querySelectorAll() 方法 returns 文档中匹配指定 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>
我有以下 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>
我想 select 3 a
标签使用原版 javascript 并从 li
开始使用 class 测试。我将它放在 parent
变量中,然后使用 querySelectorAll 尝试仅获取下一个列表中的 a
标签。但是,返回的节点列表还包括第一个 a
标记,即使它不是后代。这是我的代码:
var navChild = parent.querySelectorAll("ul > li > a");
真正奇怪的是,如果我只查询 li
个后代,我只会得到 3 个。所以我不明白为什么当我查询那个 li
的子后代时,我也得到第一个 a
标签,它比 DOM.
我知道我可以使用 jQuery 来做到这一点,但我不想使用它。
已编辑以显示我如何设置父变量
我尝试在第一个 a
标签上按下回车键后将那些 a
标签添加到 childs
变量想要包含在子节点列表中。
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
和 class test
。我不明白为什么如果我从那里 运行 查询它仍然包含第一个 a
标记。正如我之前所说,如果我只查询 ul > li
它会给我正确的 li
标签。
这是因为您的第一个 <a>
也匹配 ul > li > a
,并且由于所说的 a
仍然是调用元素 qSA 的后代,它被包含在 NodeList 中。
https://developer.mozilla.org/en-US/docs/Web/API/Element/querySelectorAll#Javascript
Element.querySelector 和 Element.querySelector 在这方面都有些古怪:虽然唯一匹配的元素必须是您调用它的元素的子元素,但选择器字符串 仍然开始在文档级别 - 它不会首先通过隔离元素及其后代来验证选择器。
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>
这是因为您试图忽略的第一个 <a>
标记仍然属于选择器规则 ul > li > a
。因此,即使您以 <li class="test">
作为根开始查询(顺便说一句,我不知道为什么其他答案说文档仍然是根),第一个子元素它finds 是 <a>
标签,实际上,它是 <li>
的子标签,而 <li>
是 <ul>
的子标签。事实上,这最终会 "above" 您指定的根被忽略。
编辑: 如果您也希望选择器规则的范围限定为根目录,则可以改用它:
parent.querySelectorAll(":scope ul > li > a");
为了进一步说明,browser CSS engines evaluate CSS rules right-to-left。在您看来,您希望浏览器从根目录(父 <li class="test">
)开始,然后找到一个 <ul>
标签,然后找到一个 <li>
标签,然后找到一个 <a>
标签。
但是,浏览器从根目录开始,然后查找根目录下的所有 <a>
标签。然后它检查 <a>
标签是否在 <li>
内,然后检查 <li>
是否在 <ul>
内。所以 <li class="parent">
标签确实是根,但之后它不遵循选择器规则的 left-to-right 层次结构,而是 right-to-left.
使用它来定义您的 var navChild = document.querySelectorAll("test > ul > li > a");
。我不得不使用 运行 示例来解决问题。这将得到你想要的 3 个香草 <a>
querySelectorAll() 方法 returns 文档中匹配指定 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>