Липкий заголовок - свиток с вкладками - PullRequest
5 голосов
/ 06 марта 2019

У меня проблемы с поведением моего липкого заголовка.

Желаемое поведение:

a) Прокрутка до того места, где нижняя часть .nav достигает вершины section, добавляет класс active для вкладки, и он остается active до тех пор, пока .nav не достигнет вершины следующего раздела.

б) Нажав на соответствующий .tab раздела всегда перемещает вас к началу этого раздела и добавляет класс active на вкладку.

Таким образом, с помощью прокрутки или щелчка, состояние active вкладок всегда сохраняется, пока .nav не перейдет в следующий section, и в этом случае состояние active перейдет на вкладку этого раздела и т. Д.

Проверьте проблемы:

1) На полпути прокрутка вниз Option Two active состояние этого .tab потеряно.

2) Использование 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();
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>

1 Ответ

2 голосов
/ 09 марта 2019

Причиной того, что ваш раздел прокручивается вверх, является смена позиций из-за добавления и удаления липкого элемента.Используйте обертку вместо липкой, чтобы всегда занимать высоту липкого элемента, есть ли он или нет.

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>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...