导入/修复Vanilla Javascript中的多个元素时的性能滚动[第2部分]

时间:2018-05-04 14:59:25

标签: javascript ecmascript-6

在我以前的post我请求帮助,在没有框架的情况下滚动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')

这导致&#34;闪烁&#34;在所有滚动中的效果,其中类被删除/添加连续(对我的整体性能有负面影响)。

有没有办法解决这个问题?

第二个问题是,当有人调整窗口大小时,我添加了一个事件监听器来更新元素的偏移量和高度值。

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

window.addEventListener('resize', updateProjectsOffsetTop);

如果我在开始滚动之前调整窗口大小,这可以正常工作。但是,如果我在启动滚动后调整窗口大小,一切都会破坏。

我无法找到更新实时值并将其传递给滚动功能的方法。我想用Vanilla ES6解决这个代码,如果可能的话,因为我试图从该规范开始学习Javascript。

我知道也许这是一个简单的问题,但我在这里学习:)

提前致谢并找到完整的JS小提琴。

&#13;
&#13;
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);
&#13;
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;
    }
&#13;
<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>
&#13;
&#13;
&#13;

1 个答案:

答案 0 :(得分:1)

您需要确保在删除和添加课程之间不会出现间歇性渲染。那些重绘会导致它在不同点重新渲染,使其闪烁。尝试在对request animation frame的调用中嵌套删除和固定类的集合。实际上你的固定功能足够小,你可以在调用它的时候设置它,就像这样:

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

在此答案中更新了您的代码段以测试您的评论,对我来说似乎正常工作:编辑:刚刚注意到我的上述示例缺少一个闭包。固定

&#13;
&#13;
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);
&#13;
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;
    }
&#13;
<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>
&#13;
&#13;
&#13;