我正在尝试创建一个静态网站,当的一个div子项进入视口时(准确地,当div元素进入视口的上50%时),该网站会将side-nav中相应的div的类更改为“活性”。它应该可以上下滚动。
到目前为止,我已经从SO上的其他线程尝试了几种解决方案,但均未成功。我认为我一直在解决这个错误。
$(window).on('scroll', function() {
$("#vars-args").each(function() {
if (elementInViewport2($(this))) {
$(this).find("#div1a").addClass("active");
}
});
});
function elementInViewport2(el) {
var top = el.offsetTop;
var left = el.offsetLeft;
var width = el.offsetWidth;
var height = el.offsetHeight;
while (el.offsetParent) {
el = el.offsetParent;
top += el.offsetTop;
left += el.offsetLeft;
}
return (
top < (window.pageYOffset + window.innerHeight) &&
left < (window.pageXOffset + window.innerWidth) &&
(top + height) > window.pageYOffset &&
(left + width) > window.pageXOffset
);
}
<script src="https://code.jquery.com/jquery-3.3.1.js" integrity="sha256-2Kok7MbOyxpgUVvAk/HJ2jigOSYS2auK4Pfzbm7uH60=" crossorigin="anonymous"></script>
<div id="side-nav">
<a href="" id="div1a">1</a>
<a href="" id="div2a">2</a>
<a href="" id="div3a">3</a>
<a href="" id="div4a">4</a>
<a href="" id="div5a">5</a>
<a href="" id="div6a">6</a>
</div>
<div id="content">
<div id="div1">
<!--content-->
</div>
<div id="div2">
<!--content-->
</div>
<div id="div3">
<!--content-->
</div>
<div id="div4">
<!--content-->
</div>
<div id="div5">
<!--content-->
</div>
<div id="div6">
<!--content-->
</div>
</div>
还要注意,内部每个div的内容都可以大于视口的大小。
我在使JavaScript正常工作时遇到了问题。另外请注意,当前的JS是从其他线程复制的。
答案 0 :(得分:1)
这可以通过使用IntersectionObserver来实现,如@cloned在注释中所述:https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
要实现这一点,您需要将一个回调函数作为参数传递,一旦isIntersecting
为 true (一个选项)后执行>对象(将阈值设置为元素的50%)和 IntersectionObserver 。
回调根据条目的 id 将活动类切换到 a 元素。
最后,我们遍历 divs 并使观察者观察它们。
const callback = (entries, observer) => {
entries.forEach(entry => {
const navItem = document.querySelector('#' + entry.target.id + 'a');
if (entry.isIntersecting) {
console.log(navItem.getAttribute('id'));
navItem.classList.add('active');
} else {
navItem.classList.remove('active');
}
});
};
const options = {
threshold: 0.5
};
const observer = new IntersectionObserver(callback, options);
const container = document.getElementById('content');
const targetElements = container.querySelectorAll('div');
targetElements.forEach(element => {
observer.observe(element);
});
这是一个 JSBin 来演示它https://jsbin.com/riyuhediso/47/edit?html,js,console,output
注意,尽管它证明了它的可行性,但并未针对可能非常重要的性能问题进行剖析,因此我不作保证。
如果您使用的是 Bootstrap ,则可以使用 ScrollSpy lib https://getbootstrap.com/docs/4.1/components/scrollspy/,还有 ScrollMagic 很棒,{{ 3}}
答案 1 :(得分:1)
您需要借助.getBoundingClientRect()
筛选出视口中的哪个元素
结帐this
并检查视口(window.innerHeight
)一半内是否有顶部和底部内容
我借助过滤器功能找出了内置函数中的目录索引,并设置了相应锚点的.active
类。
看看这段代码:
var direction = 0; // a variable to keep track of scrolled position;
$(window).on('scroll', function() {
// check if window is scrolling up or down;
if ($(window).scrollTop() > direction) { // if true, window scrolling scrolling down;
$('#side-nav').find('a').removeClass('active'); // remove active class from all anchors
$('#side-nav').find('a').eq(
// .eq() selector helps to find elements with index number, and here we pass a filter to find the content that is within the viewport;
$('#content').find('div').filter(function(index) {
return this.getBoundingClientRect().y <= (window.innerHeight / 2) && this.getBoundingClientRect().y + this.getBoundingClientRect().height > window.innerHeight / 2;
}).index()
).addClass('active');
// update the current scroll position now;
direction = $(window).scrollTop();
} else { // if false, window scrolling scrolling up;
$('#side-nav').find('a').removeClass('active'); // remove active class from all anchors
$('#side-nav').find('a').eq(
$('#content').find('div').filter(function(index) {
return this.getBoundingClientRect().y < (window.innerHeight / 2) && this.getBoundingClientRect().y + this.getBoundingClientRect().height > window.innerHeight / 2;
}).index()
).addClass('active');
// update the current scroll position now;
direction = $(window).scrollTop();
}
});
* {
margin: 0;
padding: 0;
}
#side-nav {
/* feel free to remove or change, only for testing */
position: fixed;
width: 100%;
top: 0;
padding: 15px;
}
#side-nav a {
/* feel free to remove, only for testing */
text-decoration: none;
color: grey;
margin-right: 5px;
font-size: 24px;
font-weight: bold;
}
#side-nav a.active {
color: #000;
/* sets color for the default active class */
}
#content div {
min-height: 600px;
background-color: #cecece;
border-bottom: 1px solid #fff;
box-sizing: border-box;
padding: 50px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="side-nav">
<a href="" id="div1a" class='active'>1</a>
<!-- set a default class assuming the first one will be in viewport while window loads -->
<a href="" id="div2a">2</a>
<a href="" id="div3a">3</a>
<a href="" id="div4a">4</a>
<a href="" id="div5a">5</a>
<a href="" id="div6a">6</a>
</div>
<div id="content">
<div id="div1">
<p>One</p>
</div>
<div id="div2">
<p>Two</p>
</div>
<div id="div3">
<p>Three</p>
</div>
<div id="div4">
<p>Four</p>
</div>
<div id="div5">
<p>Five</p>
</div>
<div id="div6">
<p>Six</p>
</div>
</div>
答案 2 :(得分:0)
我找到了解决此问题的方法。 注意:html side-nav div中的所有链接从id更改为class。 我知道这是一个错误的修复程序,因此,如果可以找到任何优化或更好的解决方案,我将保留此问题。
<script>
window.onload = function() {
var vars = document.getElementById('vars-args');
var als = document.getElementById('aliases')
$(window).on('scroll', function() {
$('#content').find('div').each(function(){
if (eleInView(this)){
var ele = $(this).attr('id');
document.getElementsByClassName(ele)[0].classList.add("active");
};
if (!eleInView(this)){
console.log(this);
var ele = $(this).attr('id');
document.getElementsByClassName(ele)[0].classList.remove("active");
};
});
}
)};
function eleInView(el){
var h = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
//console.log(el.getBoundingClientRect().top);
return (h < el.getBoundingClientRect().bottom && el.getBoundingClientRect().top < h);
}
</script>
<script src="https://code.jquery.com/jquery-3.3.1.js" integrity="sha256-2Kok7MbOyxpgUVvAk/HJ2jigOSYS2auK4Pfzbm7uH60=" crossorigin="anonymous"></script>
<div id="side-nav">
<a href="" class="div1">1</a>
<a href="" class="div2">2</a>
<a href="" class="div3">3</a>
<a href="" class="div4">4</a>
<a href="" class="div5">5</a>
<a href="" class="div6">6</a>
</div>
<div id="content">
<div id="div1">
<!--content-->
</div>
<div id="div2">
<!--content-->
</div>
<div id="div3">
<!--content-->
</div>
<div id="div4">
<!--content-->
</div>
<div id="div5">
<!--content-->
</div>
<div id="div6">
<!--content-->
</div>
</div>