Закрепить / исправить несколько элементов в Vanilla Javascript на свитке - PullRequest
0 голосов
/ 02 мая 2018

Я новичок в javascript и пытаюсь создать что-то со спецификацией es6.

Я бы хотел воссоздать эффекты булавки из ScrollMagic и закрепить другой раздел, пока я прокручиваю страницу вниз.

Итак, у меня есть простая HTML-разметка с верхним колонтитулом и 3 разделами:

<header class="forewords">
 <h1>Some text</h1>
</header>

<div class="wrapper">
 <section class="project" id="item1">this is section 1</section>
 <section class="project" id="item2">this is section 2</section>
 <section class="project" id="item3">this is section 3</section>
</div>

<footer class="endings">
 <h1>some text</h1>
</footer>

И я добавил несколько стилей для имитации реалистичной ситуации.

Вот логика JavaScript:

Получить все проекты:

const projects = Array.from(document.querySelectorAll('.project'));

Получить смещение всех проектов сверху и высоту всех проектов:

let projectsOffsetTop = projects.map(project => project.offsetTop);
let projectsHeight = projects.map(project => project.offsetHeight);

Создать функцию для обновления значения, если кто-то изменяет размер окна:

function updateProjectsOffsetTop() {
  projectsOffsetTop = projects.map(project => project.offsetTop);
  projectsHeight = projects.map(project => project.offsetHeight);
};

window.addEventListener('resize', updateProjectsOffsetTop);

окончательно закрепите элемент, если прокрутка больше его смещения.

function pinElement() {

  if (window.scrollY >= projectsOffsetTop[1]) {
    document.body.style.paddingTop = projectsHeight[1] +'px';
    projects[1].classList.add('fixed');
  } else {
    document.body.style.paddingTop = 0;
    projects[1].classList.remove('fixed');
  }

};

window.addEventListener('scroll', pinElement);

Но я не могу заставить его работать со всеми элементами проектов. Даже с за цикл. Какова лучшая практика? Я хочу решить эту проблему в Vanilla ES6, если это возможно.

Найдите приложенную полную js скрипку.

Спасибо

const projects = Array.from(document.querySelectorAll('.project'));
    let projectsOffsetTop = projects.map(project => project.offsetTop);
    let projectsHeight = projects.map(project => project.offsetHeight);

    function updateProjectsOffsetTop() {
      projectsOffsetTop = projects.map(project => project.offsetTop);
      projectsHeight = projects.map(project => project.offsetHeight);
    };

    function pinElement() {

      if (window.scrollY >= projectsOffsetTop[1]) {
        document.body.style.paddingTop = projectsHeight[1] +'px';
        projects[1].classList.add('fixed');
      } else {
        document.body.style.paddingTop = 0;
        projects[1].classList.remove('fixed');
      }

    };

    window.addEventListener('resize', updateProjectsOffsetTop);
    window.addEventListener('scroll', pinElement);
html {
      box-sizing: border-box;
      
    }

    *, *::before, *::after {
      box-sizing: inherit;
      margin: 0;
      padding: 0;
    }

    header, footer {
      width: 100%;
      padding: 10%;
      background-color: grey;
      position: relative;
    }

    .project {
      width: 100%;
      height: 100vh;
      position: relative;
      display: flex;
      justify-content: center;
      align-items: center;
      top: 0;
    }

    #item1 {background-color: yellow;}
    #item2 {background-color: blue;}
    #item3 {background-color: red;}


    .fixed {
      position: fixed;
    }
<header class="forewords"><h1>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Harum soluta ipsam quaerat cupiditate neque, necessitatibus amet nihil perferendis sunt minus! Exercitationem nulla inventore, aut beatae magnam, totam et minus hic.</h1>
  </header>

  <div class="wrapper">
    <section class="project" id="item1">this is section 1</section>
    <section class="project" id="item2">this is section 2</section>
    <section class="project" id="item3">this is section 3</section>
  </div>

  <footer class="endings"><h1>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Repudiandae vel, perferendis ullam totam recusandae sed repellendus cum! Molestiae, aut ut sequi eos quidem nam quo est, ad tempora inventore odit.</h1>
  </footer>

1 Ответ

0 голосов
/ 02 мая 2018

Вы предоставили удивительный MCVE для работы, поэтому большое спасибо за то, что вы потратили столько сил и времени, чтобы задать отличный вопрос. Хорошей новостью является то, что вы почти там! Ваша логика здорова, и все имеет смысл. Чего вам действительно не хватает, так это:

  • Правильное размещение логики для сброса стилей (заполнение верхней части тела и удаление класса fixed)
  • Получение индекса элемента .project, который находится ближе всего, но больше, чем высота прокрутки

В вашем методе pinElement() вы хотите сделать следующее:

  1. Сбросить / отменить все сначала
  2. Получите значение projectsOffsetTop, которое больше, чем scrollY, но ближе к нему (так что это будет элемент, который мы хотим закрепить)
  3. Отсюда получаем индекс элемента .project, которому принадлежит это значение
  4. Если индекс равен -1 (т. Е. У нас нет элемента, который соответствует критериям в пункте 2), return и остановить выполнение.
  5. В противном случае мы выполняем ту логику, которую вы используете в исходном методе, но замените 1 индексом, который мы определили на шаге 3.

Имея это в виду, вот ваш слегка переработанный pinElement() метод:

function pinElement() {

  // Reset all styles
  projects.forEach((project) => {
    document.body.style.paddingTop = 0;
    project.classList.remove('fixed');
  });

  // Get the index of the project that is closest to top
  const valueClosestToScrollY = Math.max.apply(Math, projectsOffsetTop.filter((offsetTop) => offsetTop <= window.scrollY));
  const idx = projectsOffsetTop.indexOf(valueClosestToScrollY);

  // If index is not found, we don't do anything
  if (idx === -1)
    return;

  // Otherwise, we set the appropriate styles and classes
  if (window.scrollY >= projectsOffsetTop[idx]) {
    document.body.style.paddingTop = `${projectsHeight[idx]}px`;
    projects[idx].classList.add('fixed');
  }

};

Интересный совет: вы можете использовать литералы шаблонов для этого:

document.body.style.paddingTop = `${projectsHeight[idx]}px`;

& hellip; вместо этого:

document.body.style.paddingTop = ${projectsHeight[idx] + 'px';

Вот пример проверки концепции:

const projects = Array.from(document.querySelectorAll('.project'));
let projectsOffsetTop = projects.map(project => project.offsetTop);
let projectsHeight = projects.map(project => project.offsetHeight);

function updateProjectsOffsetTop() {
  projectsOffsetTop = projects.map(project => project.offsetTop);
  projectsHeight = projects.map(project => project.offsetHeight);
};

function pinElement() {

  // Reset all styles
  projects.forEach((project) => {
    document.body.style.paddingTop = 0;
    project.classList.remove('fixed');
  });

  // Get the index of the project that is closest to top
  const valueClosestToScrollY = Math.max.apply(Math, projectsOffsetTop.filter((offsetTop) => offsetTop <= window.scrollY));
  const idx = projectsOffsetTop.indexOf(valueClosestToScrollY);
  
  // If index is not found, we don't do anything
  if (idx === -1)
    return;

  // Otherwise, we set the appropriate styles and classes
  if (window.scrollY >= projectsOffsetTop[idx]) {
    document.body.style.paddingTop = `${projectsHeight[idx]}px`;
    projects[idx].classList.add('fixed');
  }

};

window.addEventListener('resize', updateProjectsOffsetTop);
window.addEventListener('scroll', pinElement);
html {
  box-sizing: border-box;
}

*,
*::before,
*::after {
  box-sizing: inherit;
  margin: 0;
  padding: 0;
}

header,
footer {
  width: 100%;
  padding: 10%;
  background-color: grey;
  position: relative;
}

.project {
  width: 100%;
  height: 100vh;
  position: relative;
  display: flex;
  justify-content: center;
  align-items: center;
  top: 0;
}

#item1 {
  background-color: yellow;
}

#item2 {
  background-color: blue;
}

#item3 {
  background-color: red;
}

.fixed {
  position: fixed;
}
<header class="forewords">
  <h1>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Harum soluta ipsam quaerat cupiditate neque, necessitatibus amet nihil perferendis sunt minus! Exercitationem nulla inventore, aut beatae magnam, totam et minus hic.</h1>
</header>

<div class="wrapper">
  <section class="project" id="item1">this is section 1</section>
  <section class="project" id="item2">this is section 2</section>
  <section class="project" id="item3">this is section 3</section>
</div>

<footer class="endings">
  <h1>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Repudiandae vel, perferendis ullam totam recusandae sed repellendus cum! Molestiae, aut ut sequi eos quidem nam quo est, ad tempora inventore odit.</h1>
</footer>

В дополнение к этому, по соображениям производительности вы, возможно, захотите рассмотреть возможность регулирования / отмены события прокрутки, чтобы pinElement() не вызывался чрезмерно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...