【问题标题】:Select specific elements between two elements在两个元素之间选择特定元素
【发布时间】:2020-07-31 20:13:16
【问题描述】:

我给定了一些相当讨厌的 HTML,并希望遍历给定标题下的所有列表元素。不幸的是,我想跳过这两者之间的一些 cmets。

<header><h2>A</h2></header>
<ul class="list">...</ul>
<header><h2>C</h2></header>
<p>Some comment</p>
<ul class="list">...</ul>
<p>Another comment</p>
<ul class="list">...</ul>
<header><h2>B</h2></header>
<p>Some comment</p>
<ul class="list">...</ul>

我试过document.querySelectorAll('h2 ~ .list:not(h2)'),但这没有任何回报。

所以,理想情况下,我会检查每个标题,并为每个标题检索lists,类似于

const headers = document.querySelectorAll('h2');
for(let i = 0; i < headers.length; ++i)
{
  // Somehow get an Array of `list` elements between h2 i and i+1
}

【问题讨论】:

  • “但这什么都不返回” - ~ 是通用的 sibling 组合子。您的 h2.list 元素 不是 兄弟姐妹。这些列表是 header 元素的兄弟,所以你的组合器必须从它开始。
  • 而且.list:not(h2) 一开始就毫无意义——你没有一个h2 元素与该类在这里,所以你不需要首先“排除”它们。
  • 您不能遍历每个标题并获取其列表,因为该列表不是任何标题的子级...如果标题不是列表的父级无关紧要而且您不想在其中发表评论,您不能只通过 .list 类进行选择吗?老实说,有了更好的 html 结构,您就不必像这样搜索所有古怪的东西,您的代码将更容易阅读......

标签: javascript css css-selectors


【解决方案1】:

如果您只需要ul 元素,您可以将选择器简化为'header ~ .list'。这是因为h2 元素是header 的子元素并且没有兄弟姐妹,因此一般的兄弟姐妹选择器“~”不匹配。

const lists = document.querySelectorAll('header ~ .list');

console.log(lists.length);
<header><h2>A</h2></header>
<ul class="list">...</ul>
<header><h2>C</h2></header>
<p>Some comment</p>
<ul class="list">...</ul>
<p>Another comment</p>
<ul class="list">...</ul>
<header><h2>B</h2></header>
<p>Some comment</p>
<ul class="list">...</ul>

【讨论】:

    【解决方案2】:

    假设你想要 both 与它相关的 header.list,单个选择不会为你做这件事,你必须做一些遍历。 (如果您想要.lists,请参阅chazsolo's answer。)

    1. 选择header 元素。
    2. 遍历它们
      1. 在“this”header 处理你找到的任何 uls 之后循环通过兄弟姐妹 (nextElementSibling),在第一个 header 处停止

    大致:

    // Ideally, if you can narrow down this initial select, that would be good
    const headers = document.querySelectorAll("header");
    for (const header of headers) { // *** See note
        let list = header.nextElementSibling;
        while (list && list.tagName !== "HEADER") {
            if (list.tagName === "UL") {
                console.log("Found: " + list.id);
            }
            list = list.nextElementSibling;
        }
    }
    

    现场示例:

    // Ideally, if you can narrow down this initial select, that would be good
    const headers = document.querySelectorAll("header");
    for (const header of headers) { // *** See notes
        let list = header.nextElementSibling;
        while (list && list.tagName !== "HEADER") {
            if (list.tagName === "UL") {
                console.log("Found: " + list.id);
            }
            list = list.nextElementSibling;
        }
    }
    <!-- Added IDs just to make showing them easier -->
    <header><h2>A</h2></header>
    <ul class="list" id="list1">...</ul>
    <header><h2>C</h2></header>
    <p>Some comment</p>
    <ul class="list" id="list2">...</ul>
    <p>Another comment</p>
    <ul class="list" id="list3">...</ul>
    <header><h2>B</h2></header>
    <p>Some comment</p>
    <ul class="list" id="list4">...</ul>

    注意for (const header of headers):这依赖于来自querySelectorAllNodeList 是可迭代的。它被指定为可迭代的,并且在现代浏览器上是可迭代的,但稍旧的(和过时的)可能有 NodeList 而不是可迭代的。在这种情况下,您可以使用forEach。但过时的浏览器甚至没有。您可以填充 forEach 或可迭代性或两者兼有,请参阅 my answer here 了解详细信息。否则,使用老式的for 循环。 :-)

    【讨论】:

    • document.querySelectorAll('header ~ .list') 不够吗?
    • @chazsolo - 如果您不需要标题,是的,绝对。我假设(在这里我可能错了)OP 需要header 和与之相关的列表......但我不确定我为什么会这样假设。 :-)
    猜你喜欢
    • 2012-06-07
    • 2014-12-04
    • 1970-01-01
    • 1970-01-01
    • 2017-07-23
    • 1970-01-01
    • 2011-01-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多