Добавление и удаление класса, применение стилей при прокрутке

у меня проблема с добавлением и удалением классов, применением стилей при прокрутке.

в частности, когда я прокрутите страницу:

  • класс is-red все еще на первом .dot__outer группа при прокрутке вниз страницы, когда она должна быть удалена, должна быть выделена одна группа с is-red класс
  • кажется, есть проблема с моим if-statement, так как цвета остаются по умолчанию цвета и не меняются при прокрутке

ожидаемое поведение

прокрутка:

  • при прокрутке удалите класс is-red на всех divs с классом dot__outer
  • добавить класс is-red до следующего dot__outer в серии после того, как пользователь прокрутил мимо конкретной панели. т. е. если пользователь находится на второй панели, вторая группа должна быть выделена красным

точка цвета:

  • на черном фоне, точки и их границы должны быть белый
  • на белом фоне точки и их границы должны быть черными
  • в обоих случаях, каких-либо dot__outer класса is-red должно быть красный

скрипты.js

$(function() {

  function updateProgress() {
    let dot = $(".dot");

    let dotsBottom = $(".dots").offset().top + $(".dots").outerHeight();
    let panelHeaderBottom =$(".panel-1").offset().top + $(".panel-1").outerHeight();
    let panelRelatedTop = $(".panel-8").offset().top;

    // If the `dot__outer` has a class of `is-active` the dot should also be red. By default, the dot and border should be white.
    if (dot.parent().hasClass("is-red")) {
      $(this).css("background", "red");
    } else {

      // If the position of the dots is less than the bottom of the header or greater than the top of the related section, the dots are white. Otherwise, the dots are black
      if (dotsBottom < panelHeaderBottom || dotsBottom > panelRelatedTop) {
        $(this).css("background", "#000");

      } else {
        $(this).css("background", "#fff");
      }
    }

    $(".panel").each(function(index) {
      let currentPosition = $(window).scrollTop();
      let panelTop = $(this).offset().top;
      let panelBottom = $(this).offset().top + $(this).outerHeight();

      if ((currentPosition > panelTop) && (currentPosition < panelBottom)) {        
        $(".dot__outer").removeClass("is-red");
        $(".dot__outer").eq(index).addClass("is-red");
      } else {
        $(".dot__outer").eq(0).addClass("is-red");
      }
    });
  }

  $(window).scroll(function() {
    updateProgress();
  });
});
.HTML-код
<div class="panels">
  <div class="panel panel-1">Panel #1</div>
  <div class="panel panel-2">Panel #2</div>
  <div class="panel panel-3">Panel #3</div>
  <div class="panel panel-4">Panel #4</div>
  <div class="panel panel-5">Panel #5</div>
  <div class="panel panel-6">Panel #6</div>
  <div class="panel panel-7">Panel #7</div>
  <div class="panel panel-8">Panel #8</div>
</div>

<div class="dots">

  <div class="dot__outer is-red">
    <div class="dot"></div>
  </div>

  <div class="dot__outer">
    <div class="dot"></div>
  </div>

  <div class="dot__outer">
    <div class="dot"></div>
  </div>

  <div class="dot__outer">
    <div class="dot"></div>
  </div>

  <div class="dot__outer">
    <div class="dot"></div>
  </div>

  <div class="dot__outer">
    <div class="dot"></div>
  </div>

  <div class="dot__outer">
    <div class="dot"></div>
  </div>

  <div class="dot__outer">
    <div class="dot"></div>
  </div>
</div>

сайт CodePen

https://codepen.io/yacoubian/pen/PBOVKw?editors=1010

обновление

проблема прокрутки исправлена, обновлен codpen.

4 ответов


вот мое решение. Это динамически проверяет положение панели и сравнивает его с каждой точкой, а затем применяет класс для стиля css.

сайт CodePen: https://codepen.io/tylerfowle/pen/QBaBgO

  1. я добавил light и dark класс на панелях html.
  2. в JS мы обнаруживаем, находится ли панель в окне просмотра, если это какой класс у нее есть (светлый или темный).
  3. мы тогда цикл через каждый из .dot__outer элементы и посмотреть, в какой панели они находятся, и применить правильный класс. Мы используем середину, чтобы определить, на какой панели находится большинство точек.

$(function() {
  let dotClass = "dark";

  function updateProgress() {
    let viewportTop = $(window).scrollTop();
    let viewportBot = viewportTop + $(window).height();

    $(".panel").each(function(index) {
      // save the ref to the current panel for use in the dot loop
      let $this = $(this);
      let panelTop = $(this).offset().top;
      let panelBot = panelTop + $(this).outerHeight();

      // add class based on panel that is within viewport, remove from siblings
      if ((viewportTop > panelTop) && (viewportTop < panelBot)) {
        $(".dot__outer").eq(index).addClass("is-red").siblings().removeClass("is-red");
      }

      $(".dot__outer").each(function(){
        let dotTop = $(this).offset().top;
        let dotMid = dotTop + $(this).outerHeight()/2;
        let dotBot = dotTop + $(this).outerHeight();

        if ($this.hasClass("light")) {
          dotClass = "light";
        } else {
          dotClass = "dark";
        }

        if (panelTop < dotMid && panelBot > dotMid) {
          $(this).removeClass("dark light").addClass(dotClass);
        }

      });

    });
  }

  $(window).scroll(function() {
    updateProgress();
  });

});
body {
  margin: 0;
}

.panel {
  width: 100vw;
  height: 100vh;
  border-bottom: 1px solid red;
  font-size: 24px;
  font-weight: 700;
  color: #000;
}
.panel.panel-1, .panel.panel-8 {
  background: #000;
  color: #fff;
}

.dots {
  position: fixed;
  bottom: 48px;
  right: 48px;
}

.dot {
  width: 5px;
  height: 5px;
  background: white;
  border-radius: 50%;
}

.dot__outer {
  margin-bottom: 16px;
  padding: 8px;
  border: 1px solid white;
}
.dot__outer.light {
  border-color: black;
}
.dot__outer.light .dot {
  background: black;
}
.dot__outer.dark {
  border-color: white;
}
.dot__outer.dark .dot {
  background: white;
}
.dot__outer.is-red {
  border: 1px solid red !important;
}
.dot__outer.is-red .dot {
  background: red !important;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="panels">
  <div class="panel panel-1 dark">Panel #1</div>
  <div class="panel panel-2 light">Panel #2</div>
  <div class="panel panel-3 light">Panel #3</div>
  <div class="panel panel-4 light">Panel #4</div>
  <div class="panel panel-5 light">Panel #5</div>
  <div class="panel panel-6 light">Panel #6</div>
  <div class="panel panel-7 light">Panel #7</div>
  <div class="panel panel-8 dark">Panel #8</div>
</div>

<div class="dots">

  <div class="dot__outer is-red">
    <div class="dot"></div>
  </div>

  <div class="dot__outer">
    <div class="dot"></div>
  </div>

  <div class="dot__outer">
    <div class="dot"></div>
  </div>

  <div class="dot__outer">
    <div class="dot"></div>
  </div>

  <div class="dot__outer">
    <div class="dot"></div>
  </div>

  <div class="dot__outer">
    <div class="dot"></div>
  </div>

  <div class="dot__outer">
    <div class="dot"></div>
  </div>

  <div class="dot__outer">
    <div class="dot"></div>
  </div>
</div>

Это еще один подход, который вы могли бы принять:

function updateProgress() {
    let dotsBottom = $(".dots").offset().top + $(".dots").outerHeight();
    let dotBorder = $(".dot__outer");

    let headerBottom = $(".panel-1").offset().top + $(".panel-1").outerHeight();
    let relatedTop = $(".panel-8").offset().top;

    $(".panel").each(function(index) {
        let currentPosition = $(window).scrollTop();
        let panelTop = $(this).offset().top;
        let panelBottom = $(this).offset().top + $(this).outerHeight();

        if (currentPosition > panelTop && currentPosition < panelBottom) {
            dotBorder.removeClass("is-red");
            dotBorder.eq(index).addClass("is-red").children().css("background", "red");

            if (dotsBottom < headerBottom || dotsBottom > relatedTop) {
                dotBorder.not(".is-red").children().css("background", "#fff");
            } else {
                dotBorder.not(".is-active").children().css("background", "#000");
            }
        }
    });
}

Я бы, вероятно, решил некоторые проблемы с помощью CSS, особенно часть окраски.

вот идея, где я уменьшил код JS, чтобы только добавить / удалить класс на основе простого деления, чтобы найти индекс.

затем я использовал какой-то трюк CSS, чтобы иметь окраску ящиков:

  • для границы я использовал box-shadow чтобы создать вторую границу с другим цветом, так что будет виден только один в зависимости от фон.
  • для фона, я определил окраску, используя градиент, который является инвертный окраска сайте. Я сделал его фиксированным, и я отрегулировал положение на прокрутке с помощью переменной CSS.

запустите фрагмент на полной странице для лучшего опыта

$(function() {

  function updateProgress() {
        let currentPosition = $(window).scrollTop();
        let index = Math.floor(currentPosition/$(window).height());
        
        $(".is-red").removeClass("is-red");
        $(".dot__outer").eq(index).addClass("is-red");
        $('.dot').css('--p',(-currentPosition)+'px');
  }

  $(window).scroll(function() {
    updateProgress();
  });
});
body {
  margin: 0;
}

.panel {
  height: 100vh;
  border-bottom: 1px solid red;
  font-size: 24px;
  font-weight: 700;
  color: #000;
}

.panel.panel-1,
.panel.panel-8 {
  background: #000;
  color: #fff;
}

.dots {
  position: fixed;
  top: 48px;
  right: 48px;
}

.dot {
  width: 5px;
  height: 5px;
  background: 
    linear-gradient(to bottom,
      #fff 0%,#fff 12.5%,
      #000 12.5%,#000 87.5%,
      #fff 87.5%,#fff 100%) no-repeat;
  background-size:200vw 800vh;
  background-attachment:fixed;
  background-position:0 calc(var(--p,48px) + 48px);
  border-radius: 50%;
}

.dot__outer {
  border: 1px solid #fff;
  margin-bottom: 16px;
  padding: 8px;
  box-shadow:1px 1px 0px #000,
             -1px 1px 0px #000,
             1px -1px 0px #000,
             -1px -1px 0px #000;
}

.dot__outer.is-red {
  border: 1px solid red;
  box-shadow:1px 1px 0px red,
             -1px 1px 0px red,
             1px -1px 0px red,
             -1px -1px 0px red;
}

.dot__outer.is-red .dot {
  background: red;
}
<script
  src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<div class="panels">
  <div class="panel panel-1">Panel #1</div>
  <div class="panel panel-2">Panel #2</div>
  <div class="panel panel-3">Panel #3</div>
  <div class="panel panel-4">Panel #4</div>
  <div class="panel panel-5">Panel #5</div>
  <div class="panel panel-6">Panel #6</div>
  <div class="panel panel-7">Panel #7</div>
  <div class="panel panel-8">Panel #8</div>
</div>

<div class="dots">

  <div class="dot__outer is-red">
    <div class="dot"></div>
  </div>

  <div class="dot__outer">
    <div class="dot"></div>
  </div>

  <div class="dot__outer">
    <div class="dot"></div>
  </div>

  <div class="dot__outer">
    <div class="dot"></div>
  </div>

  <div class="dot__outer">
    <div class="dot"></div>
  </div>

  <div class="dot__outer">
    <div class="dot"></div>
  </div>

  <div class="dot__outer">
    <div class="dot"></div>
  </div>

  <div class="dot__outer">
    <div class="dot"></div>
  </div>
</div>

Я все еще изучаю javascript, но я знаю, что Bootstrap имеет ScrollSpy который сделает это для вас, используя то, что уже находится в начальной загрузке.js. Эти учебники также могут помочь вам, если вы не хотите переключать тему на Bootstrap.

  • прокрутка страницы до ID

  • см. кодовое перо" индикаторы положения прокрутки " Закари Олсона. Вот последняя часть URL codepen.io/zacharyolson/pen/uaEzD

  • изменение цвета страницы при прокрутке в JS Fiddle -jsfiddle.net/ncuydr9y/1