在Vanilla JS中滚动到下一部分并返回顶部没有ID - 没有JQUERY

时间:2017-02-23 03:11:07

标签: javascript jquery ecmascript-6

我使用了一个经过修改的jQuery脚本,可以滚动没有ID的部分,并在到达文档末尾时返回顶部。

因为我是JS的新手,并试图改进和学习我想摆脱jQuery依赖。

我已经设法使其部分工作但失败并且迷茫地找到了jQueries Offset方法的替代方法。

  

这是修改过的jQuery脚本:



// scoll to next section and back to top
var $scrollSection = $('section');
var $scrollTrigger = $('.section_trigger');
var nextSection = 1;

$scrollTrigger.on('click', function() {
  $(this).removeClass('go-to-top');

  // If reached the last section, scroll back to the top on the next click:
  if (nextSection >= $scrollSection.length) {
    $('html, body').animate({
      scrollTop: 0
    }, 1000);
    nextSection = 0;
    return;
  }

  // if we scroll down increment section counter
  while ($('body').scrollTop() > $($scrollSection[nextSection]).offset().top) {
    nextSection++;
  }

  // If next section is the last, add class to rotate arrow:
  if (nextSection === ($scrollSection.length - 1)) {
    $(this).addClass('go-to-top');
  }

  // Move to next section and increment counter
  $('html, body').animate({
    scrollTop: $($scrollSection[nextSection]).offset().top
  }, 1000);
  nextSection++;
});

// turn arrow when scrolled to footer
$(window).scroll(function() {
  if ($(window).scrollTop() + $(window).height() == $(document).height()) {
    $(".section_trigger--side").addClass('go-to-top');
  } else {
    $(".section_trigger--side").removeClass('go-to-top');
  }
});

.box_0 {
  background-color: grey;
  height: 100vh;
  width: 100vw;
}

.box_1 {
  background-color: green;
  height: 50vh;
  width: 100vw;
}

.box_2 {
  background-color: blue;
  height: 50vh;
  width: 100vw;
}

.box_3 {
  background-color: yellow;
  height: 20vh;
  width: 100vw;
}

footer {
  background-color: pink;
  height: 40vh;
  width: 100vw;
}

/* styling for the section trigger */
.section_trigger svg {
  height: 60%;
  left: 20%;
  position: absolute;
  top: 20%;
  width: 60%;
}

/** @define c-scroll-nav */
.section_trigger {
  background: hsla(0, 0%, 0%, 0.45);
  border: 0;
  border-radius: 50%;
  cursor: pointer;
  height: 50px;
  width: 50px;
}

.section_trigger:hover {
  background: black;
}

.section_trigger--center {
  position: absolute;
  left: 50%;
  transform: translate(0, -50%);
  bottom: 12px;
  transform: rotate(270deg);
}

.section_trigger--side {
  bottom: 12px;
  position: fixed;
  right: 12px;
  transform: rotate(270deg);
}

.go-to-top {
  transform: rotate(90deg);
}

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span class="section_trigger section_trigger--center">
  <svg viewBox="0 0 100 100"><path d="M 10,50 L 60,100 L 70,90 L 30,50  L 70,10 L 60,0 Z" fill="white" class="arrow"></path></svg>
</span>
<span class="section_trigger section_trigger--side">
  <svg viewBox="0 0 100 100"><path d="M 10,50 L 60,100 L 70,90 L 30,50  L 70,10 L 60,0 Z" fill="white" class="arrow"></path></svg>
</span>
<section>
  <div class="box_0"></div>
</section>
<section>
  <div class="box_2"></div>
</section>
<section>
  <div class="box_3"></div>
</section>
<section>
  <div class="box_1"></div>
</section>
<section>
  <div class="box_2"></div>
</section>
<section>
  <div class="box_3"></div>
</section>
<footer></footer>
&#13;
&#13;
&#13;

  

这是我的Vanilla JS方法:

&#13;
&#13;
// Debuging
window.onscroll = function() {
  //console.log('top: '  + (window.pageYOffset || document.documentElement.scrollTop));
  // console.log('section: '  + (window.pageYOffset || document.scrollSection[nextSection].scrollTop));
  // console.log(nextSection);
  // console.log(scrollSection[0]);
}

/*
 * Helper Function: Vanilla version of jQuery scrollTop
 */
function scrollTo(element, to, duration) {
  if (duration <= 0) return;
  let difference = to - element.scrollTop;
  let perTick = difference / duration * 50;

  setTimeout(() => {
    element.scrollTop = element.scrollTop + perTick;
    if (element.scrollTop == to) return;
    scrollTo(element, to, duration - 10);
  }, 10);
}

/*
 * Main Function: Scroll to section elements and back to top
 */
const scrollSection = document.getElementsByTagName('section');
const scrollTrigger = document.getElementsByClassName('section_trigger')[1];
let nextSection = 0;

// turn arrow back arround after clicked to return to top
scrollTrigger.addEventListener('click', () => {
  scrollTrigger.classList.remove('go-to-top');
  console.log('removed class `go-to-top`');

  // If reached the last section, scroll back to the top on the next click:
  if (nextSection >= scrollSection.length) {
    function runScroll() {
      scrollTo(document.body, 0, 1000);
      nextSection = 0;
      console.log('Scrolled back to Top');
    }
  }

  // if we scroll down increment section counter
  while (document.body.scrollTop > document.scrollSection[nextSection].getBoundingClientRect().scrollTop) { //doesnt work , cant next section scrollSection undefined
    nextSection++;
    console.log('incremented counter to' + nextSection);
  }

  // If next section is the last, add go-to-top class to rotate arrow:
  if (nextSection === (scrollSection.length - 1)) {
    scrollTrigger.classList.add('go-to-top');
    console.log('added class `go-to-top`');
  }

  // Move to next section and increment counter
  function runScroll() {
    scrollTo(document.scrollSection[nextSection].getBoundingClientRect().scrollTop, 0, 1000); //doesnt work , cant next section scrollSection undefined
    nextSection++;
    console.log('Scrolled one section down');
  }

});

/*
 * Helper Function: vanilla JS get document height and window width and height
 */
const body = document.body;
const html = document.documentElement;

// document height
const documentHeight = Math.max(body.scrollHeight, body.offsetHeight,
  html.clientHeight, html.scrollHeight, html.offsetHeight);

// window width and height
const windowWidth = window.innerWidth || document.documentElement.clientWidth || body.clientWidth;
const windowHeigth = window.innerHeight || document.documentElement.clientHeight || body.clientHeight;

// turn arrow when scrolled to footer
window.onscroll = function() {
  if (window.getBoundingClientRect() + windowHeigth == documentHeight) { // not sure if getBoundingClientRect is the right choice since its relative to the viewport
    scrollTrigger.classList.add('go-to-top');
  } else {
    scrollTrigger.classList.remove('go-to-top');
  }
};
&#13;
.box_0 {
  background-color: lightgreen;
  height: 100vh;
  width: 100vw;
}

.box_1 {
  background-color: magenta;
  height: 50vh;
  width: 100vw;
}

.box_2 {
  background-color: blue;
  height: 50vh;
  width: 100vw;
}

.box_3 {
  background-color: yellow;
  height: 20vh;
  width: 100vw;
}

footer {
  background-color: pink;
  height: 40vh;
  width: 100vw;
}

/* styling for the section trigger */
.section_trigger svg {
  height: 60%;
  left: 20%;
  position: absolute;
  top: 20%;
  width: 60%;
}

/** @define c-scroll-nav */
.section_trigger {
  background: hsla(0, 0%, 0%, 0.45);
  border: 0;
  border-radius: 50%;
  cursor: pointer;
  height: 50px;
  width: 50px;
}

.section_trigger:hover {
  background: black;
}

.section_trigger--center {
  position: absolute;
  left: 50%;
  transform: translate(0, -50%);
  bottom: 12px;
  transform: rotate(270deg);
}

.section_trigger--side {
  bottom: 12px;
  position: fixed;
  right: 12px;
  transform: rotate(270deg);
}

.go-to-top {
  transform: rotate(90deg);
}
&#13;
<span class="section_trigger section_trigger--center">
  <svg viewBox="0 0 100 100"><path d="M 10,50 L 60,100 L 70,90 L 30,50  L 70,10 L 60,0 Z" fill="white" class="arrow"></path></svg>
</span>
<span class="section_trigger section_trigger--side go-to-top">
  <svg viewBox="0 0 100 100"><path d="M 10,50 L 60,100 L 70,90 L 30,50  L 70,10 L 60,0 Z" fill="white" class="arrow"></path></svg>
</span>
<section>
  <div class="box_0"></div>
</section>
<section>
  <div class="box_2"></div>
</section>
<section>
  <div class="box_3"></div>
</section>
<section>
  <div class="box_1"></div>
</section>
<section>
  <div class="box_2"></div>
</section>
<section>
  <div class="box_3"></div>
</section>
<footer></footer>
&#13;
&#13;
&#13;

我认为我没有正确使用getBoundingClientRect()方法,我也不确定是否应该相对于视口使用它。

除此之外,我不知道它的有效和正确方法是否一般,我还读到可以使用油门提高性能?方法....非常感谢,非常感谢他们。

1 个答案:

答案 0 :(得分:1)

抱歉,我没有时间完成,但我已经做了一些更新。单击中心滚动触发器时代码不会触发错误,但它还没有工作。我现在发帖保存我的答案,并会根据需要更新。

在做这类事情时,我的建议是分段实施。例如,使用工作的jQuery代码,然后在纯JS中一次替换一个函数或小块。它将更容易调试。

一些变化:

  1. if (window.pageYOffset + windowHeight == documentHeight) {
  2. const scrollTrigger = document.getElementsByClassName('section_trigger')[0];
  3. 代码:

    &#13;
    &#13;
    // Debuging
    window.onscroll = function() {
      // console.log('top: '  + (window.pageYOffset || document.documentElement.scrollTop));
      // console.log('section: '  + (window.pageYOffset || document.scrollSection[nextSection].scrollTop));
      // console.log(nextSection);
      // console.log(scrollSection[0]);
    }
    
    /*
     * Helper Function: Vanilla version of jQuery scrollTop
     */
    
    function scrollTo(element, to, duration) {
      if (duration <= 0) return;
      let difference = to - element.scrollTop;
      let perTick = difference / duration * 50;
    
      setTimeout(() => {
        element.scrollTop = element.scrollTop + perTick;
        if (element.scrollTop == to) return;
        scrollTo(element, to, duration - 10);
      }, 10);
    }
    
    /*
     * Main Function: Scroll to section elements and back to top
     */
    
    const scrollSection = document.getElementsByTagName('section');
    const scrollTrigger = document.getElementsByClassName('section_trigger')[0];
    let nextSection = 0;
    
    // turn arrow back arround after clicked to return to top
    scrollTrigger.addEventListener('click', () => {
      scrollTrigger.classList.remove('go-to-top');
      console.log('removed class `go-to-top`');
    
      // If reached the last section, scroll back to the top on the next click:
      if (nextSection >= scrollSection.length) {
        function runScroll() {
          scrollTo(document.body, 0, 1000);
          nextSection = 0;
          console.log('Scrolled back to Top');
        }
      }
    
      scrollTo(document.body, 0, 1000);
    
      // if we scroll down increment section counter
      while (document.body.scrollTop > scrollSection[nextSection].getBoundingClientRect().scrollTop) { //doesnt work , cant next section scrollSection undefined
        nextSection++;
        console.log('incremented counter to' + nextSection);
      }
    
      // If next section is the last, add go-to-top class to rotate arrow:
      if (nextSection === (scrollSection.length - 1)) {
        scrollTrigger.classList.add('go-to-top');
        console.log('added class `go-to-top`');
      }
    
      // Move to next section and increment counter
      function runScroll() {
        scrollTo(document.scrollSection[nextSection].getBoundingClientRect().scrollTop, 0, 1000); //doesnt work , cant next section scrollSection undefined
        nextSection++;
        console.log('Scrolled one section down');
      }
    
    });
    
    /*
     * Helper Function: vanilla JS get document height and window width and height
     */
    
    const body = document.body;
    const html = document.documentElement;
    
    // document height
    const documentHeight = Math.max(body.scrollHeight, body.offsetHeight,
      html.clientHeight, html.scrollHeight, html.offsetHeight);
    
    // window width and height
    const windowWidth = window.innerWidth || document.documentElement.clientWidth || body.clientWidth;
    const windowHeight = window.innerHeight || document.documentElement.clientHeight || body.clientHeight;
    
    // turn arrow when scrolled to footer
    window.onscroll = function() {
      if (window.pageYOffset + windowHeight == documentHeight) { // not sure if getBoundingClientRect is the right choice since its relative to the viewport
        scrollTrigger.classList.add('go-to-top');
      } else {
        scrollTrigger.classList.remove('go-to-top');
      }
    };
    &#13;
    .box_0 {
      background-color: lightgreen;
      height: 100vh;
      width: 100vw;
    }
    
    .box_1 {
      background-color: magenta;
      height: 50vh;
      width: 100vw;
    }
    
    .box_2 {
      background-color: blue;
      height: 50vh;
      width: 100vw;
    }
    
    .box_3 {
      background-color: yellow;
      height: 20vh;
      width: 100vw;
    }
    
    footer {
      background-color: pink;
      height: 40vh;
      width: 100vw;
    }
    
    
    /* styling for the section trigger */
    
    .section_trigger svg {
      height: 60%;
      left: 20%;
      position: absolute;
      top: 20%;
      width: 60%;
    }
    
    
    /** @define c-scroll-nav
      */
    
    .section_trigger {
      background: hsla(0, 0%, 0%, 0.45);
      border: 0;
      border-radius: 50%;
      cursor: pointer;
      height: 50px;
      width: 50px;
    }
    
    .section_trigger:hover {
      background: black;
    }
    
    .section_trigger--center {
      position: absolute;
      left: 50%;
      transform: translate(0, -50%);
      bottom: 12px;
      transform: rotate(270deg);
    }
    
    .section_trigger--side {
      bottom: 12px;
      position: fixed;
      right: 12px;
      transform: rotate(270deg);
    }
    
    .go-to-top {
      transform: rotate(90deg);
    }
    &#13;
    <span class="section_trigger section_trigger--center">
      <svg viewBox="0 0 100 100"><path d="M 10,50 L 60,100 L 70,90 L 30,50  L 70,10 L 60,0 Z" fill="white" class="arrow"></path></svg>
    </span>
    <span class="section_trigger section_trigger--side go-to-top">
      <svg viewBox="0 0 100 100"><path d="M 10,50 L 60,100 L 70,90 L 30,50  L 70,10 L 60,0 Z" fill="white" class="arrow"></path></svg>
    </span>
    <section>
      <div class="box_0"></div>
    </section>
    <section>
      <div class="box_2"></div>
    </section>
    <section>
      <div class="box_3"></div>
    </section>
    <section>
      <div class="box_1"></div>
    </section>
    <section>
      <div class="box_2"></div>
    </section>
    <section>
      <div class="box_3"></div>
    </section>
    <footer></footer>
    &#13;
    &#13;
    &#13;