如何获取当前显示在屏幕上的第一个可见DOM元素? 我试过类似的方法 var el = document.elementFromPoint(x,y) 并在while循环中增加y坐标,但问题是当文档上有css多列时,它不起作用,在这种情况下,返回的是< html >标记,而不是实际的元素。有没有什么方法可以让我真正得到屏幕上(左上角)的元素,它适用于css列?
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');
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();
2条答案
按热度按时间qvtsj1bj1#
这是一个非常基本的例子,它只获取距离
top
最远的元素。这只是一个开始,因为您可能还需要考虑left
偏移量。您需要排除
body
和html
元素(如下所示),因为它们总是第一个。Fiddle
t5fffqht2#
一个好主意,特别是如果你有很多元素,是做一个二分搜索。下面是一个完整的例子。这段代码的目标是在侧栏中突出显示当前在
<main>
中可见的部分的标题。这是我老师的一个程序的HTML手册。它目前是live here,但应该很快被移动here。
我可能会错过JavaScript的一些有趣或更优化的功能。太复杂了!
由于这是网站上的一个常见功能,我很想知道他们是否使用相同的技术,或者他们是否有一个更好的(或更坏的?))一个。