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

iqxoj9l9  于 2023-05-22  发布在  jQuery
关注(0)|答案(2)|浏览(447)

如何获取当前显示在屏幕上的第一个可见DOM元素?
我试过类似的方法
var el = document.elementFromPoint(x,y)
并在while循环中增加y坐标,但问题是当文档上有css多列时,它不起作用,在这种情况下,返回的是< html >标记,而不是实际的元素。有没有什么方法可以让我真正得到屏幕上(左上角)的元素,它适用于css列?

qvtsj1bj

qvtsj1bj1#

这是一个非常基本的例子,它只获取距离top最远的元素。这只是一个开始,因为您可能还需要考虑left偏移量。
您需要排除bodyhtml元素(如下所示),因为它们总是第一个。

Fiddle

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');
t5fffqht

t5fffqht2#

一个好主意,特别是如果你有很多元素,是做一个二分搜索。下面是一个完整的例子。这段代码的目标是在侧栏中突出显示当前在<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手册。它目前是live here,但应该很快被移动here
我可能会错过JavaScript的一些有趣或更优化的功能。太复杂了!
由于这是网站上的一个常见功能,我很想知道他们是否使用相同的技术,或者他们是否有一个更好的(或更坏的?))一个。

相关问题