javascript - HTML - 如何滚动整个部分而不在中间停止?

标签 javascript html css sass

我需要完成什么:

我的网站由多个部分组成,每个部分占据整个页面。当用户尝试向下滚动时,我想要完成的是:

  1. 在滚动达到一定速度阈值之前,页面根本不会移动。
  2. 当滚动达到阈值时向下滚动整个页面。

示例网站:


我尝试过的:

  1. CSS scroll-snap-align:此方法仅在用户停止滚动后捕捉滚动。

示例代码:

<div id="app">
    <section id="page1">Page 1 Content</section>

    <section id="page2">Page 2 Content</section>
</div>
#app
{
    height: 100vh;
}

section
{
    position: relative;
    width: 100%;
    height: 100%;
}

最佳答案

这里首先要注意的是,scroll 事件无法取消。因此,只能通过在 wheelmousewheel 事件上附加事件监听器来完成(如果还需要触摸屏支持,则为 touchmove)。

通过使用这些,我能够想出这个。这里的想法是维护一个计数器,它将在每个wheel事件上增加/减少其值。如果计数器达到某个阈值,就会触发滚动功能。停止鼠标滚轮后,计数器将重置回 0、N 毫秒。

因此,为了触发滚动功能,必须在N毫秒的时间限制内转动鼠标滚轮一定次数才能达到阈值。

这种方法的缺点是 body 元素被赋予了 overflow:hidden 属性来隐藏滚动条。否则,用户将无法滚动页面而达不到预期的效果。如果这不是问题,则可以删除 overflow 属性。 此外,本示例中未处理 touchmove 事件,但其实现也类似。

$(document).ready(function() {

  const COUNTER_THRESHOLD = 5; // Change this to decrease/increase senstivity
  const COUNTER_RESET_DURATION = 400;

  let animating = false;
  let counter = 0;

  function resetDelta() {
    counter = 0
  }
  let deboucncedReset = debounce(resetDelta, COUNTER_RESET_DURATION);

  function handleScroll(event) {
    //event.wheelDelta can be positive or negative based on the direction of scroll
    counter += 1 * (Math.sign(event.wheelDelta));

    //Scroll down if value of counter is negative and absolute value is greater than threshold
    if (!animating && (Math.abs(counter) >= COUNTER_THRESHOLD) && counter < 0) {
      let targetSection = $('section.active').next('section');
      if (targetSection.length) {
        scrollToSection(targetSection);
      }
    }
    //Scroll up if value of counter is positive and absolute value is greater than threshold
    else if (!animating && (Math.abs(counter) >= COUNTER_THRESHOLD) && counter > 0) {
      let targetSection = $('section.active').prev('section');
      if (targetSection.length) {
        scrollToSection(targetSection);
      }
    }
    // prevent default scrolling behaviour of mouse wheel
    event.preventDefault()

    //Reset counter to 0 , 400 miliseconds after stopping the mousewheel
    deboucncedReset()
  }

  function scrollToSection(target) {
    animating = true;
    $('html, body').animate({
      scrollTop: target.offset().top
    }, 800, function() {
      animating = false;
      $('section.active').removeClass('active');
      target.addClass('active');
    });
  }

  function debounce(func, delay) {
    let debounceTimer
    return function() {
      const context = this
      const args = arguments
      clearTimeout(debounceTimer)
      debounceTimer
        = setTimeout(() => func.apply(context, args), delay)
    }
  }


  //Test support for passive listeners
  let supportsPassive = false;
  try {
    let options = Object.defineProperty({}, 'passive', {
      get: function() {
        supportsPassive = true;
      }
    });
    window.addEventListener("testPassive", null, options);
    window.removeEventListener("testPassive", null, options);
  } catch (e) {}

  let wheelOptions = supportsPassive ? {
    passive: false
  } : false;

  // Older browsers used 'mousewheel' event
  let wheelEvent = 'onwheel' in document.createElement('div') ? 'wheel' : 'mousewheel';

  document.addEventListener(wheelEvent, handleScroll, wheelOptions);

});
body {
  overflow: hidden;
}

#app {
  height: 100vh;
}

section {
  position: relative;
  width: 100%;
  height: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="app">

  <section id="page1" class="active">
    <h2>Section 1</h2>
    <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Dolores sequi quaerat officia non sunt sit, assumenda ullam itaque eos natus sed, aliquam adipisci consectetur nemo eum a reprehenderit fuga, ut consequatur beatae tenetur debitis. Officiis,
      quod vitae sapiente tempore odit, quas nemo minus cupiditate laboriosam et cum accusantium porro quam hic soluta? Blanditiis assumenda suscipit accusamus laborum modi, cumque consequatur velit asperiores eius consectetur deserunt fugiat aperiam
      recusandae quibusdam, dolore alias doloribus ut quis, voluptatem dolorum dolores harum unde magni. Commodi ducimus distinctio, quos ipsa, itaque illo nostrum laboriosam corporis sunt ad perferendis laborum ut natus magni dolore unde asperiores!</p>
  </section>

  <section id="page2">
    <h2>Section 2</h2>
    <p>Lorem ipsum dolor sit amet consectetur, adipisicing elit. Repellendus, consequuntur enim ab dolorem rem, animi voluptates ipsam sequi nisi, dolores quod. Unde molestias facere autem nam error laboriosam eum nisi! Placeat voluptatum voluptate aspernatur.
      Laboriosam nulla eaque culpa corporis consequuntur suscipit temporibus sed, totam, quia sit aut beatae sunt nihil ducimus fugit dolorum inventore minus dolorem modi eius! Aliquid distinctio sed dolorem? Quos ipsum optio fugit asperiores eligendi
      vitae saepe nostrum. Eius minus recusandae quaerat. Fuga inventore temporibus doloremque sequi officia voluptatibus explicabo ad? Distinctio molestiae cupiditate obcaecati eum consequatur, error, illo quidem, maxime expedita veniam assumenda alias
      culpa laudantium!</p>
  </section>
</div>

为了使其功能齐全,还需要处理箭头键和空格键。但这应该是一件相对容易处理的事情。

关于javascript - HTML - 如何滚动整个部分而不在中间停止?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63144144/

相关文章:

html - 汉堡菜单项折叠成 2 行

html - 将 div 置于图像之上

html - 整个页面上的 CSS 过滤器

javascript - 使用异步和等待未处理的拒绝(InvalidTokenError)

javascript - $resource 无法从 json 获取数组

html - 使用CSS更改背景图像的颜色

javascript - 使用 JavaScript 将 html 写入另一个 html

javascript - 未在 "mysite.com/"处加载时,RequireJS 不遵循相对路径

javascript - 如何正确阻止 Node.JS 服务器应用程序中的 IP 地址?

javascript - 在 jquery 中通过列表项值选择的预填充列表项