Производительность при закреплении / исправлении нескольких элементов в Vanilla Javascript на свитке [часть 2] - PullRequest
0 голосов
/ 04 мая 2018

В моем предыдущем посте я попросил помочь исправить некоторые разделы при прокрутке в Vanilla ES6 без фреймворков.

Простая структура HTML:

<header class="forewords"><h1>Lorem some</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 something.</h1>
</footer>

Это основная функция, которая выполняет работу:

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


  // 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('scroll', pinElement);

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

Прежде всего, каждый раз, когда я сначала прокручиваю, я вызываю функцию classList.remove('.fixed') для всего, и внезапно я вызываю classList.add('.fixed') для выбранного элемента.

Это вызывает эффект "мерцания" в течение всей прокрутки, когда класс удаляется / добавляется непрерывно (что, по-моему, отрицательно влияет на общую производительность).

Есть ли способ решить эту проблему?

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

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

window.addEventListener('resize', updateProjectsOffsetTop);

Это прекрасно работает, если я изменю размеры окон перед началом прокрутки. Но если я изменил размеры окон после запуска прокрутки, все сломалось.

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

Я знаю, что, возможно, это простая проблема, но я здесь, чтобы учиться :)

Заранее спасибо и приложите полную JS Fiddle.

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


      // 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>

1 Ответ

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

Вы должны убедиться, что между удалением и добавлением класса нет прерывистых визуализаций. Эти перерисовки заставляют его перерисовываться в разных точках, заставляя его мерцать. Попробуйте вложить удаление и установить фиксированный класс внутри вызова в запрос кадра анимации . На самом деле ваша функция закрепления достаточно мала, и вы, вероятно, можете установить все это внутри вызова так:

function pinElement() {
  window.requestAnimationFrame(() => {
    // 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);


    // 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('scroll', pinElement);

Обновил ваш фрагмент в этом ответе, чтобы проверить ваш комментарий. Кажется, он работает нормально для меня: РЕДАКТИРОВАТЬ: Только что заметил, что в приведенном выше примере отсутствует закрытие. фиксированный

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() {
      window.requestAnimationFrame(() =>{
      // 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);


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