I would like to combine a large number of "pages", eg, blog posts, into a single HTML page, probably using a <section> for each one, and each would have an id so that I can jump to it via a link fragment. What I'd like to be able to do is to detect the id of the section the top of the visible part of the page is within, so that whenever it changes as a result of the user scrolling the page, I can change some navigation buttons that are anchored to the top of the window. Presumably, this would happen in a JavaScript event handler that gets called whenever scrolling stops. Is there a DOM function that can find out what HTML element is at the top of the window? If I knew that, I could traverse its ancestors until I find a section element.
<ul id="top-menu">
<li class="active">
<a href="#">Top</a>
</li>
<li>
<a href="#foo">Foo</a>
</li>
<li>
<a href="#bar">Bar</a>
</li>
<li>
<a href="#baz">Baz</a>
</li>
</ul>
<a id="foo">Foo</a>
<a id="bar">Bar</a>
<a id="baz">Baz</a>
and use this javascript
// Cache selectors
var lastId,
topMenu = $("#top-menu"),
topMenuHeight = topMenu.outerHeight()+15,
// All list items
menuItems = topMenu.find("a"),
// Anchors corresponding to menu items
scrollItems = menuItems.map(function(){
var item = $($(this).attr("href"));
if (item.length) { return item; }
});
// Bind click handler to menu items
// so we can get a fancy scroll animation
menuItems.click(function(e){
var href = $(this).attr("href"),
offsetTop = href === "#" ? 0 : $(href).offset().top-topMenuHeight+1;
$('html, body').stop().animate({
scrollTop: offsetTop
}, 300);
e.preventDefault();
});
// Bind to scroll
$(window).scroll(function(){
// Get container scroll position
var fromTop = $(this).scrollTop()+topMenuHeight;
// Get id of current scroll item
var cur = scrollItems.map(function(){
if ($(this).offset().top < fromTop)
return this;
});
// Get the id of the current element
cur = cur[cur.length-1];
var id = cur && cur.length ? cur[0].id : "";
if (lastId !== id) {
lastId = id;
// Set/remove active class
menuItems
.parent().removeClass("active")
.end().filter("[href='#"+id+"']").parent().addClass("active");
}
});
and use this css
body {
height: 6000px;
font-family: Helvetica, Arial;
}
#top-menu {
position: fixed;
z-index: 1;
background: white;
left: 0;
right: 0;
top: 0;
}
#top-menu li {
float: left;
}
#top-menu a {
display: block;
padding: 5px 25px 7px 25px;
width: 4em;
text-align: center;
-webkit-transition: .5s all ease-out;
-moz-transition: .5s all ease-out;
transition: .5s all ease-out;
border-top: 3px solid white;
color: #aaa;
text-decoration: none;
}
#top-menu a:hover {
color: #000;
}
#top-menu li.active a {
border-top: 3px solid #333;
color: #333;
}
#foo {
position: absolute;
top: 400px;
}
#bar {
position: absolute;
top: 800px;
}
#baz {
position: absolute;
top: 1200px;
}
here is working demo link
The answer was buried in there, under lots of unnecessary junk related to jQuery and particular button formats. But I managed to figure out it can be done in simple JavaScript. First, since my page doesn't change dynamically, as soon as it's loaded I build an array of section ids indexed by their vertical page offsets:
var locs = []
var pos = window.pageYOffset || documentElement.scrollTop
Array.prototype.forEach.call(document.getElementsByTagName("section"),
function(n) {
locs[Math.round(n.getBoundingClientRect().top + pos] = n.id
})
Then, after any scroll, I fetch the new scroll offset and search the list:
var sect
pos = window.pageYOffset || document.docuemntElement.scrollTop
try {
locs.forEach(function(id, offs) {
if (offs <= pos)
sect = id
else
throw null
])
}
catch (e) {}
and the answer is in sect
. I can also jump to a particular section by doing window.scrollTo(0, locs.indexOf(sect))
. Pretty simple.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.