javascript - 使用 JavaScript 向下滚动 div 时平滑滚动,向上滚动时卡顿且缓慢

标签 javascript html css

我有一个简单的页面,我将在右侧放置一个大表单,在左侧放置一个导航菜单,允许用户跳转到大表单的各个部分(这也可以用于大文章) - 现在为了模拟尺寸,我用 CSS 添加了一个大的底部填充)。右列的样式已使用 height: 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),请参阅完整内容的 jsbin https://jsbin.com/nidevaj/edit?html,css,js,output

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

最佳答案

您可以将 CSS 属性 scroll-behavior 设置为 smooth(大多数现代浏览器都支持),这样就不再需要 Javascript。只需给 anchor 标记一个 #href 加上要滚动到的 anchor 标记的 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,你可以使用 for 循环与 window.scrollTosetTimeout 以及 setInterval 用于平滑滚动。我为此写了一个函数。要滚动到某个元素,请提供该元素的 offsetTop 作为 pos 参数。

function scrollToSmoothly(pos, time) {
  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) {
  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) {
  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>


有关平滑滚动的更全面的方法列表,请参阅我的回答 here .

关于javascript - 使用 JavaScript 向下滚动 div 时平滑滚动,向上滚动时卡顿且缓慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51693706/

相关文章:

css - 使列在 Bootstrap 中固定位置

javascript - CSS 和 JS 文件仅在 Google Chrome 上加载

html - 如何在图像上的文本中添加对比度

javascript - 单页应用程序 - 大型 DOM - 慢

html - ul li 链接不起作用(在导航栏中)

javascript - 在有序/无序列表上按回车键在每个 <li> 元素后添加 <br>

javascript - 我可以安全地在 JavaScript 中的 Event 对象上设置自定义属性吗?

javascript - 空对象原型(prototype)未定义

javascript - 数据属性的数据表搜索

javascript - 无法在移动 Chrome 中从 blob url 读取音频