使用JavaScript向下滚动div时,可以流畅地滚动,向上滚动又会变得又慢又慢

时间:2018-08-05 11:03:00

标签: javascript html css

我有一个简单的页面,我将在右侧放置一个大表格,在左侧创建一个导航菜单,使用户可以跳至该大表格的各个部分(这也可用于大型文章-现在为了模拟尺寸,我在CSS中添加了一个较大的底部填充)。右栏的样式已设置为适合使用高度:100vh的窗口的高度。

当单击右侧的链接并且节offsetTop大于其父项的scrollTop时,滚动是平滑的。我使用JavaScript setTimeout,并使用循环设置超时的时间间隔,这太棒了!但是,如果我想向上滚动,那是该节的offsetTop小于其父级的scrollTop,我会遇到问题-它变硬,缓慢且无法真正工作...我已经看了太久了因此,如果有人可以帮助我,我将非常感激。这是我的JavaScript函数

function scrollToAchor(where, event) {
  event.stopPropagation();
  var element = document.querySelector('.aims-form__form').querySelector('a[name="' + where + '"]');
  var to = element.offsetTop - 30;
  var from = document.querySelector('.aims-form__form').scrollTop
  let timeOut = 0;

  if(to >= from) {
    for(let i = from; i <= to; i+=5) {
      // this works and is great!!!
      setTimeout(function () {
        document.querySelector('.aims-form__form').scrollTop = i;
      }, i/2);
    }
  } else {

    for(let k = from; k >= to; k-=5) {
      // I need to set the timeout Interval so the animation is smooth but it is really slow
      // with the above setInterval above we are counting up... How do I get this smooth
      timeOut = timeOut + (to + 15) / 2;

      setTimeout(function () {
        document.querySelector('.aims-form__form').scrollTop = i;
      }, timeOut);
    }
  }
}

这不应该使我陷入困境,但是我无法摆脱困境,现在我有一个精神障碍。要更好地理解滚动功能,这里是HTML,但是要获得完整图片(包括必要的CSS),这里是完整https://jsbin.com/nidevaj/edit?html,css,js,output

的jsbin
  <div class="aims-form">
    <div class="aims-form__navigation">
      <ul>
        <li>
          <a onClick="scrollToAchor('section1', event)" class="aims-form__anchor">Section 1</a>
        </li>
        <li>
          <a onClick="scrollToAchor('section2', event)" class="aims-form__anchor">Section 2</a>
        </li>
        <li>
          <a onClick="scrollToAchor('section3', event)" class="aims-form__anchor">Section 3</a>
        </li>
        <li>
          <a onClick="scrollToAchor('section4', event)" class="aims-form__anchor">Section 4</a>
        </li>
      </ul>
    </div>
    <div class="aims-form__form">
      <section>
        <a name="section1"></a>
        Section 1 
        <br>
        ... content lots of content
      </section>
      <section>
        <a name="section2"></a>
        Section 2 
        <br>
        ... content lots of content
      </section>
      <section>
        <a name="section3"></a>
        Section 3 
        <br>
        ... content lots of content
      </section>
      <section>
      <a name="section4"></a>
        Section 4 
        <br>
        ... content lots of content
      </section>
  </div>
</div>

1 个答案:

答案 0 :(得分:1)

您可以将CSS属性scroll-behavior设置为smooth(大多数现代浏览器都支持),从而无需使用Javascript。只需给锚标签添加href中的#,再加上锚标签的name即可滚动到正常滚动,除了更平滑之外。

section{
  margin: 500px 0px;
}
html, body{
  scroll-behavior: smooth;
}
 <div class="aims-form">
    <div class="aims-form__navigation">
      <ul>
        <li>
          <a href="#section1">Section 1</a>
        </li>
        <li>
          <a href="#section2">Section 2</a>
        </li>
        <li>
          <a href="#section3">Section 3</a>
        </li>
        <li>
          <a href="#section4">Section 4</a>
        </li>
      </ul>
    </div>
    <div class="aims-form__form">
      <section>
        <a name="section1"></a>
        Section 1 
        <br>
        ... content lots of content
      </section>
      <section>
        <a name="section2"></a>
        Section 2 
        <br>
        ... content lots of content
      </section>
      <section>
        <a name="section3"></a>
        Section 3 
        <br>
        ... content lots of content
      </section>
      <section>
      <a name="section4"></a>
        Section 4 
        <br>
        ... content lots of content
      </section>
  </div>
</div>

如果要使用Javascript,可以将forwindow.scrollTo以及setTimeoutsetInterval循环一起使用,以实现平滑滚动。我已经为此编写了一个函数。要滚动到某个元素,请提供元素的offsetTop作为pos参数。

function scrollToSmoothly(pos, time) {
  /*Time is only applicable for scrolling upwards*/
  /*Code written by hev1*/
  /*pos is the y-position to scroll to (in pixels)*/
  if (isNaN(pos)) {
    throw "Position must be a number";
  }
  if (pos < 0) {
    throw "Position can not be negative";
  }
  var currentPos = window.scrollY || window.screenTop;
  if (currentPos < pos) {
    var t = 10;
    for (let i = currentPos; i <= pos; i += 10) {
      t += 10;
      setTimeout(function() {
        window.scrollTo(0, i);
      }, t / 2);
    }
  } else {
    time = time || 2;
    var i = currentPos;
    var x;
    x = setInterval(function() {
      window.scrollTo(0, i);
      i -= 10;
      if (i <= pos) {
        clearInterval(x);
      }
    }, time);
  }
}

section{
  margin: 500px 0px;
}
<div class="aims-form">
    <div class="aims-form__navigation">
      <ul>
        <li>
          <a onClick="scrollToAchor('section1', event)" class="aims-form__anchor">Section 1</a>
        </li>
        <li>
          <a onClick="scrollToAchor('section2', event)" class="aims-form__anchor">Section 2</a>
        </li>
        <li>
          <a onClick="scrollToAchor('section3', event)" class="aims-form__anchor">Section 3</a>
        </li>
        <li>
          <a onClick="scrollToAchor('section4', event)" class="aims-form__anchor">Section 4</a>
        </li>
      </ul>
    </div>
    <div class="aims-form__form">
      <section>
        <a name="section1"></a>
        Section 1 
        <br>
        ... content lots of content
      </section>
      <section>
        <a name="section2"></a>
        Section 2 
        <br>
        ... content lots of content
      </section>
      <section>
        <a name="section3"></a>
        Section 3 
        <br>
        ... content lots of content
      </section>
      <section>
      <a name="section4"></a>
        Section 4 
        <br>
        ... content lots of content
        <button onClick="scrollToTop()">
        Back To Top
        </button>
      </section>
  </div>
</div>
<script>
function scrollToSmoothly(pos, time) {
  /*Time is only applicable for scrolling upwards*/
  /*Code written by hev1*/
  /*pos is the y-position to scroll to (in pixels)*/
  if (isNaN(pos)) {
    throw "Position must be a number";
  }
  if (pos < 0) {
    throw "Position can not be negative";
  }
  var currentPos = window.scrollY || window.screenTop;
  if (currentPos < pos) {
    var t = 10;
    for (let i = currentPos; i <= pos; i += 10) {
      t += 10;
      setTimeout(function() {
        window.scrollTo(0, i);
      }, t / 2);
    }
  } else {
    time = time || 2;
    var i = currentPos;
    var x;
    x = setInterval(function() {
      window.scrollTo(0, i);
      i -= 10;
      if (i <= pos) {
        clearInterval(x);
      }
    }, time);
  }
}
function scrollToAchor(where, event) {
  event.stopPropagation();
  var element = document.querySelector('.aims-form__form').querySelector('a[name="' + where + '"]');
  scrollToSmoothly(element.offsetTop); 
}
function scrollToTop(){
  scrollToSmoothly(0);
}
</script>

如果要使div的内容平滑滚动,可以使用上述功能,将window.scrollTo替换为elem.scrollTop,然后将元素的offsetTop传入pos滚动到元素。

section{
  margin: 500px 0px;
}
<div style="border: 1px solid black; margin: auto; height: 250px; width: 50%; overflow-y: auto;" id="parent">
<div class="aims-form">
    <div class="aims-form__navigation">
      <ul>
        <li>
          <a onClick="scrollToAnchor('section1', event)" class="aims-form__anchor">Section 1</a>
        </li>
        <li>
          <a onClick="scrollToAnchor('section2', event)" class="aims-form__anchor">Section 2</a>
        </li>
        <li>
          <a onClick="scrollToAnchor('section3', event)" class="aims-form__anchor">Section 3</a>
        </li>
        <li>
          <a onClick="scrollToAnchor('section4', event)" class="aims-form__anchor">Section 4</a>
        </li>
      </ul>
    </div>
    <div class="aims-form__form">
      <section>
        <a name="section1"></a>
        Section 1 
        <br>
        ... content lots of content
      </section>
      <section>
        <a name="section2"></a>
        Section 2 
        <br>
        ... content lots of content
      </section>
      <section>
        <a name="section3"></a>
        Section 3 
        <br>
        ... content lots of content
      </section>
      <section>
      <a name="section4"></a>
        Section 4 
        <br>
        ... content lots of content
        <p/>
        <button onClick="scrollToTopOfDiv()">
        Back To Top
        </button>
      </section>
  </div>
</div>
</div>
<script>
function scrollToSmoothlyInsideElement(elem, pos, time) {
  /*Time is only applicable for scrolling upwards*/
  /*Code written by hev1*/
  /*pos is the y-position to scroll to (in pixels)*/
  if (isNaN(pos)) {
    throw "Position must be a number";
  }
  if (pos < 0) {
    throw "Position can not be negative";
  }
  var currentPos = elem.scrollTop;
  if (currentPos < pos) {
    var t = 10;
    for (let i = currentPos; i <= pos; i += 10) {
      t += 10;
      setTimeout(function() {
       elem.scrollTop = i;
      }, t / 2);
    }
  } else {
    time = time || 2;
    var i = currentPos;
    var x;
    x = setInterval(function() {
      elem.scrollTop = i;
      i -= 10;
      if (i <= pos) {
        clearInterval(x);
      }
    }, time);
  }
}
function scrollToAnchor(where, event){
	event.stopPropagation();
  var element = document.querySelector('.aims-form__form').querySelector('a[name="' + where + '"]');
  var parent = document.querySelector('#parent');
  scrollToSmoothlyInsideElement(parent, element.offsetTop);
}
function scrollToTopOfDiv(){
  var elem = document.querySelector('#parent');
  scrollToSmoothlyInsideElement(elem, 0);
}
</script>