Skip to content

如何选择某类的最后一个元素? #99

@hushicai

Description

@hushicai

在牛客网上偶然看到这样一个面试题:

有很多li标签且顺序不固定,怎么把最后一个class为b的li改为红色:

<ul>
  <li class="a" />
  <li class="b" />
  <li class="b" />
  <li class="a" />
  ...
</ul>

刚看到这道题,第一想法是通过js来解决:

const nodes = document.querySelectorAll('ul > .b');
const node = nodes[nodes.length - 1];
node.style.backgroundColor = 'red';

这样虽然可以解决,但是看起来比较冗余。

可不可以通过css伪类来解决呢?

:last-child

document.querySelector('ul > .b:last-child')`; // null

找不到元素。

:last-of-type

document.querySelector('ul > .b:last-of-type')`; // null

也找不到元素。

刚开始有点不解,翻了一下标准文档,才发现,.b:last-of-type的工作原理是这样的:

  • 通过.b找到对应元素
  • 确定元素的标签类型(上面例子是li
  • 找到最后一个li.b元素。
  • 如果它是父元素下的最后一个同类型子元素,则命中;否则不命中。

上面的例子中,由于都是li元素,所以通过.b选出来的最后一个元素,并非是父元素下最后一个li标签,所以找不到元素。

核心问题在于元素的标签类型是否相同。

如果是不同的元素类型, 则结果不一样。

案例1:

  <div>
    <div>这是一个干扰段落。</div>
    <p class="p">这是第一个段落。</p>
    <p class="p">这是第二个段落。</p>
    <p class="p">这是第三个段落。</p>
    <div>这是一个干扰段落。</div>
  </div>

  <script>
    document.querySelector('div > .p:last-of-type')`; // <p class="p">这是第三个段落。</p>
  </script>

先找到第一个.p元素,然后确定标签类型是p,所以最后一个同类型的.p元素就是“第三个段落”。

案例2:

  <div>
    <div>这是一个干扰段落。</div>
    <p class="p">这是第一个段落。</p>
    <p class="p">这是第二个段落。</p>
    <p class="p">这是第三个段落。</p>
    <div class="p">这是一个干扰段落。</div>
  </div>

  <script>
    document.querySelector('div > .p:last-of-type')`; // <p class="p">这是第三个段落。</p>
  </script>

最后一个div的class虽然也是.p,但是由于不是p标签,所以命中的是“第三段落”的p标签。

nth-last-child

最后只能通过nth-last-child(2)来解决了。

document.querySelector('ul .b:nth-last-child(2)'); //  <li class="b">b</li>

参考文章

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions