如何获取当前显示在屏幕上的第一个可见DOM元素?

问题描述 投票:0回答:2

如何获取当前显示在屏幕上的第一个可见 DOM 元素?

我尝试过类似的事情

var el = document.elementFromPoint(x, y) 

并在

y
循环中增加
while
坐标,但问题是当文档上有 CSS 多列时,它不起作用,在这种情况下,返回
<html>
标签,而不是实际元素。

有什么方法可以真正获取屏幕左上角适用于 CSS 列的元素吗?

javascript jquery html multiple-columns
2个回答
3
投票

这是一个非常基本的示例,仅获取距

top
最远的元素。这只是一个开始,因为您可能还想考虑
left
偏移。

您需要排除

body
html
元素(如下所示),因为它们始终是第一个。

小提琴

var first;
$(':visible').not('body, html').each(function() {
    if (typeof first == 'undefined') {
        first = $(this);
    } else if ($(this).offset().top < first.offset().top) {
        first = $(this);
    }
});
first.addClass('highlight');

0
投票

一个好主意是进行二分搜索,尤其是当您有很多元素时。这是一个完整的例子。此代码的目标是在侧边栏中突出显示当前在

<main>
中可见的部分标题。

const asideTocItems = Array.from(asideToc.querySelectorAll('li'))
    .map(item => ({ item: item, heading: document.getElementById(getItemTargetId(item)) })),
  mainBlock = document.querySelector('main');
function updateAsideToc() {
  // Binary search to find the first heading which is above the top
  let searchTop = 0, searchBot = asideTocItems.length;
  while (searchTop + 1 < searchBot) {
    const searchMid = (searchTop + searchBot) >> 1, heading = asideTocItems[searchMid].heading;
    if (heading.offsetTop - getElemFontSize(heading) <= mainBlock.scrollTop) {
      searchTop = searchMid;
    } else {
      searchBot = searchMid;
    }
  }
  // Previously marked items are unmarked
  for (const item of asideToc.querySelectorAll('li.current')) {
    item.classList.remove('current');
  }
  // We mark items starting from the found one
  const visibleBottomY = mainBlock.scrollTop + mainBlock.clientHeight;
  for (let itemNum = searchTop; itemNum < asideTocItems.length; ++itemNum) {
    // If the current heading is below the bottom, it’s time to leave
    const heading = asideTocItems[itemNum].heading;
    if (heading.offsetTop + getElemFontSize(heading) >= visibleBottomY) {
      break;
    }
    let item = asideTocItems[itemNum].item;
    item.classList.add('current');
    // Parents are expanded
    do {
      item.classList.remove('collapsed');
    } while ((item = item.parentElement.closest('li')) != null);
  }
  // Previously expanded items are collapsed back, unless they still have current items
  for (const item of asideToc.querySelectorAll('.hasChild:not(.current):not(.collapsed)')) {
    if (item.querySelector('.current') == null) {
      item.classList.add('collapsed');
    }
  }
  // We scroll the sidebar so that all marked items are visible
  const currentItems = asideToc.querySelectorAll('.current > a');
  if (currentItems.length > 0) {
    const first = currentItems[0], last = currentItems[currentItems.length - 1],
      container = asideToc.closest('aside');
    if (first.offsetTop < container.scrollTop) {
      container.scrollTop = first.offsetTop;
    } else if (last.offsetTop + last.offsetHeight > container.scrollTop + container.clientHeight) {
      container.scrollTop = last.offsetTop + last.offsetHeight - container.clientHeight;
    }
  }
}
mainBlock.onscroll = updateAsideToc;
updateAsideToc();

这是我老师的一个程序的HTML手册。目前它已上线此处,但应该很快就会移至此处

我可能会错过一些有趣的或者更优化的 JavaScript 功能。太复杂了…!

由于这是网站上的常见功能,我很好奇他们是否使用相同的技术或者他们是否有更好(或更差?)的技术。

© www.soinside.com 2019 - 2024. All rights reserved.