我的粘性标头的行为存在问题。
期望的行为:
a)滚动到
.nav
底部碰到section
顶部的位置 标签上的active
类,它将保持active
到.nav
到达下一部分的顶部。b)点击相应的 部分的
.tab
始终将您导航到该部分的顶部,并将active
类添加到选项卡。
因此,通过滚动或单击,选项卡的active
状态始终保持到.nav
进入下一个section
,在这种情况下为active
状态转到该部分的标签等。
测试问题:
1)中途向下滚动Option Two
的{{1}}的{{1}}状态。
2)使用active
滚动到.tab
的顶部,而不是所选scrollTop
的顶部。
.container
section
class StickyNavigation {
constructor() {
this.currentId = null;
this.currentTab = null;
let self = this;
$(".tab").click(function() {
self.onTabClick(event, $(this));
});
$(".container").scroll(() => {
this.onScroll();
});
$(".container").resize(() => {
this.onResize();
});
}
/*Scrolls down to Tab selection*/
onTabClick(event, element) {
event.preventDefault();
let scrollTop = $(element.attr("href")).offset().top;
if (!$(".nav").hasClass("nav--top")) {
scrollTop = scrollTop;
}
$(".container").animate({
scrollTop: scrollTop
}, 600);
}
onScroll() {
this.navPosition();
this.tabAnimation();
}
navPosition() {
let offset = $(".sticky").offset().top + $(".sticky").height();
if ($(".container").scrollTop() > offset) {
$(".nav").addClass("nav--top");
} else {
$(".nav").removeClass("nav--top");
}
}
tabAnimation() {
$("section").each(function() {
var actual = $(this),
actualHeight = actual.height(),
actualAnchor = $(".sticky").find('a[href="#' + actual.attr("id") + '"]');
if (
actual.offset().top <= $(".container").scrollTop() &&
actual.offset().top + actualHeight > $(".container").scrollTop()
) {
actualAnchor.addClass("active");
} else {
actualAnchor.removeClass("active");
}
});
}
}
new StickyNavigation();
答案 0 :(得分:3)
如果您能够调整自己的html
结构,我想这可能对您有所帮助。
我在我的一个项目中做了这样的事情,它就来了:
您需要借助.getBoundingClientRect()
检出this
并检查标题顶部右上方是否有任何内容。
我借助filter
方法来查找内置函数中的内容索引,并设置了相应锚点的.active
类。
更新:因为您有固定的标头和粘性标头。并且它们之间有一个 hero 部分,我将第一个标头的position
设置为fixed
,然后添加相同的高度(在本例中为100px
)像padding-top
上的body
一样,因此hero元素不会被裁剪掉。
现在,由于我们知道第一个固定标头的高度为sticky
,因此粘性标头的位置为top
,并且100px
设置为100px
。
现在,脚本应检查固定页眉的高度和粘性页眉的 Y 轴位置>
现在来看一下代码片段:
var direction = 0; // a variable to keep track of scrolled position;
$(window).on('scroll', function() {
var headerElBottom = document.getElementById('side-nav').getBoundingClientRect().y + document.getElementById('header').getBoundingClientRect().height;
// 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 <= headerElBottom && this.getBoundingClientRect().y + this.getBoundingClientRect().height > headerElBottom;
}).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 < headerElBottom && this.getBoundingClientRect().y + this.getBoundingClientRect().height > headerElBottom;
}).index()
).addClass('active');
// update the current scroll position now;
direction = $(window).scrollTop();
}
});
* {
margin: 0;
padding: 0;
}
body {
padding-top: 100px;
}
#side-nav {
/* feel free to remove or change, only for testing */
position: sticky;
width: 100%;
top: 100px;
padding: 35px;
border-bottom: 1px solid black;
background-color: #fff;
box-sizing: border-box;
}
.header {
padding: 40px;
background-color: #cecece;
position: fixed;
top: 0;
height: 100px;
width: 100%;
box-sizing: border-box;
font-size: 20px;
}
.hero {
padding: 60px 40px;
background-color: #967373;
height: 200px;
box-sizing: border-box;
font-size: 20px;
}
#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: red;
/* sets color for the default active class */
}
#content div {
min-height: 900px;
background-color: #cecece;
border-bottom: 1px solid #fff;
box-sizing: border-box;
padding: 100px 50px;
}
#content div:nth-child(2) {
background-color: #e25454;
}
#content div:nth-child(3) {
background-color: #5d5dff;
}
#content div:nth-child(4) {
background-color: #4db14d;
}
#content div:nth-child(5) {
background-color: #cece52;
}
#content div:nth-child(6) {
background-color: #cc9023;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="header" id="header">Fixed Header</div>
<div class="hero">Hero section</div>
<div id="side-nav">
<a href="#div1" id="div1a" class='active'>One</a>
<!-- set a default class assuming the first one will be in viewport while window loads -->
<a href="#div2" id="div2a">Two</a>
<a href="#div3" id="div3a">Three</a>
<a href="#div4" id="div4a">Four</a>
<a href="#div5" id="div5a">Five</a>
<a href="#div6" id="div6a">Six</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>
答案 1 :(得分:2)
您的部分滚动到顶部的原因是由于添加和 去除粘性元素。使用包装纸代替粘纸,以始终占据 粘性元素是否存在。
class StickyNavigation {
constructor() {
this.currentId = null;
this.currentTab = null;
this.setup();
this.onResize();
let self = this;
$(".tab").click(function(event) {
self.onTabClick(event, $(this));
});
$(".container").scroll(() => {
this.onScroll();
});
$(window).resize(() => {
this.onResize();
});
}
setup() {
this.$sticky = $('.sticky');
window.stk = this.$sticky;
this.$stickyWrap = $('<div>').insertAfter(this.$sticky);
this.$sticky.appendTo(this.$stickyWrap);
}
/*Scrolls down to Tab selection*/
onTabClick(event, element) {
event.preventDefault();
let $targetElement = $(element.attr("href"));
let positionTop = $targetElement.position().top;
let scrollTop = $('.container').scrollTop();
$(".container").animate({
scrollTop: scrollTop - this.stickyOuterHeight + positionTop
}, 600);
}
onScroll() {
this.navPosition();
this.tabAnimation();
}
onResize() {
this.stickyOuterHeight = this.$sticky.outerHeight();
this.$sticky.width(this.$stickyWrap.width());
this.$stickyWrap.css('minHeight', this.stickyOuterHeight);
}
navPosition() {
if (this.$stickyWrap.position().top < 0) {
this.$sticky.addClass("fixed");
} else {
this.$sticky.removeClass("fixed");
}
}
tabAnimation() {
let desiredSpace = this.stickyOuterHeight + 10;
$("section").each(function() {
let actual = $(this),
actualHeight = actual.height(),
actualAnchor = $(".sticky").find('a[href="#' + actual.attr("id") + '"]');
let actualTop = actual.position().top;
let actualBottom = actualTop + actualHeight;
if (actualTop < desiredSpace && actualBottom > desiredSpace) {
actualAnchor.addClass("active");
} else {
actualAnchor.removeClass("active");
}
});
}
}
$(function() {
new StickyNavigation();
});
body {
position: fixed;
display: flex;
flex-direction: column;
top: 0;
bottom: 0;
left: 0;
right: 0;
overflow: hidden;
}
section {
height: 600px;
border: 2px solid white;
background: blue;
}
section:nth-child(2) {
background: red;
}
.container {
flex: 1;
display: flex;
position: relative;
flex-direction: column;
overflow: auto;
}
.long {
height: 1200px;
}
.header {
height: 75px;
background: green;
}
.hero {
background: silver;
flex: 0;
border: 1px solid;
}
.nav {
background: white;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
position: relative;
}
.sticky {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.sticky.fixed {
position: fixed;
top: 83px;
}
.tab {
padding: 30px 45px;
position: relative;
}
.tab.active {
background: #6567c5;
color: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="header">
<h1>Header</h1>
</div>
<div class="container">
<div class="hero">
<h1>Hero</h1>
</div>
<div class="sticky">
<nav role="navigation" class="nav">
<a class="tab" href="#One">Option One</a>
<a class="tab" href="#Two">Option Two</a>
</nav>
</div>
<div class="main">
<section id="One">
Content One
</section>
<section class="long" id="Two">
Content Two
</section>
</div>
</div>