粘性头部 - 伴随标签滚动

6

我的粘性标题行为出现问题。

期望的行为:

a)滚动到 .nav 的底部与 section 的顶部相遇时,将 active 类添加到选项卡,并保持其处于 active 状态,直到 .nav 到达下一个 section 的顶部。

b)单击相应的 section 的 .tab 将始终导航到该 section 的顶部,并将 active 类添加到选项卡。

因此,无论是通过滚动还是点击,选项卡的 active 状态始终保持,直到 .nav 跨入下一个 section,在这种情况下,active 状态转移到该 section 的选项卡等等。

测试问题:

1) 在滚动到 Option Two 的一半时,该 .tabactive 状态丢失。

2) 使用 scrollTop 滚动到所选 section 的顶部,而不是 .container 的顶部。

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();
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;
}

.nav--top {
  position: fixed;
  top: 75px;
}

.sticky {
  background: white;
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  position: relative;
}

.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">
    </section>
    <section class="long" id="Two">
    </section>
  </div>
</div>
</div>


包含任何额外的库可以吗?还是你只想要一个仅依赖于jQuery的答案? - karthick
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>


谢谢Munim。你的解决方案非常好,但在使用Firefox测试时我遇到了一个错误。 "message": "ReferenceError: event is not defined", "filename": "https://stacksnippets.net/js", "lineno": 115, "colno": 7 - Kyle Underhill
现在它可以工作了。Tab-click事件处理程序缺少一个事件参数。 - Munim Munna

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接