【问题标题】:How to stop inertial scrolling in a web app如何在 Web 应用程序中停止惯性滚动
【发布时间】:2021-09-04 21:27:49
【问题描述】:

我正在为年幼的孩子创建一个网络应用程序,他们可以在其中水平滚动非常宽的图片。年幼的孩子可能会疯狂地滑动触摸屏。我想允许惯性滚动(因为它很有趣),但要限制它,以便儿童用户不会快速向后和向前滚动到最后,错过中间的所有好东西。

在惯性滚动期间,会生成mousewheel 事件。我曾希望在此事件中使用event.preventDefault(),以便在特定点停止惯性滚动。但是,似乎如果您不在特定操作中的第一个 mousewheel 事件上运行 preventDefault(),则不会阻止以下事件。

下面的代码 sn-p 提供了一个演示。它包含一个可以滚动的元素,直到其 scrollLeft 的值达到 5000。JavaScript 包含一个 mousewheel 事件侦听器,当 scrollLeft 的值大于 2500 时,它会显式调用 event.preventDefault()

我曾希望这会中途停止惯性滚动。但是没有。

运行 sn-p 然后使用鼠标垫(或触摸屏)向左滑动可滚动元素。你会看到:

  1. 如果您提供足够的惯性,元素将滚动一直向左。对event.preventDefault() 的条件调用无效。
  2. mousewheel 事件持续发出最多 5 秒(取决于您用于滑动的能量)。即使元素完全向左滚动,它们也会继续发射。

但是,如果您向左滚动超过 2500,然后尝试向右滑动,则不会发生任何事情。 first mousewheel 事件的默认操作被阻止,因此惯性滚动永远不会开始。

我的问题是:在滚动到达某个点后,有没有办法完全阻止 mousewheel 事件的发出?额外问题:有没有办法确定特定滑动手势的惯性大小?

我有一个解决方法来限制scrollLeft 的值,但这意味着在发出最后一个mousewheel 事件之前,孩子将无法再次滑动。

const output = document.getElementById("output");
const container = document.getElementById("container");
container.addEventListener("mousewheel", mousewheel, false);

let startTime = 0
let timeOut = 0

function mousewheel(event) {
  const time = getTime()
  const scrollLeft = Math.round(container.scrollLeft * 10) / 10;
  output.innerText = time + "s\n" + scrollLeft;

  clearTimeout(timeOut)
  timeOut = setTimeout(() => startTime = 0, 100)

  if (scrollLeft > 2500) {
    event.preventDefault();
    return false;
  }
}

function getTime() {
  const time = + new Date()
  if (!startTime) {
    startTime = time;
  }
  return (time - startTime) % 10000 / 1000
}
body {
  margin: 0;
  height: 100px;
}

div#container {
  width: 500px;
  height: 100%;
  background-color: green;
  overflow: auto;
}

div#content {
  width: 5500px; /* Allows scrollLeft up to 5000 */
  height: 100%;
  background-color: red;
  clip-path: polygon(0 0, 100% 0, 100% 100%)
}
<div id="container">
  <div id="content"></div>
</div>
<pre id="output">0</p>

【问题讨论】:

    标签: javascript html mousewheel eventemitter


    【解决方案1】:

    我认为您不能阻止浏览器发出事件。这就是为什么必须使用preventDefault。因此,为了回答您的问题,

    1. 没有。但是,您可以劫持事件并使用它来满足您的预期行为。
    2. 是的。 mousewheel 事件的 wheelDelta 值越大,惯性越大。请务必注意 mousewheel 已弃用。您应该使用wheel 事件。在这种情况下,事件将具有您可以使用的 deltaXdeltaY 值。

    考虑到这些因素,您可以轻松建立自己的行为。我简化了代码以强调策​​略。简而言之,您设置图片的center 和该中心周围的interesting 区域。您总是阻止默认行为(劫持事件)。如果scrollLeft 属性位于center 周围的interesting 区域之外,则根据deltaX 移动滚动条(使用可选的multiplier)。如果它在该区域内,您可以将scrollLeft 中的更改除以它。请注意,在示例中,除数可能太大而无法强调效果。

    const output = document.getElementById("output");
    const container = document.getElementById("container");
    container.addEventListener("wheel", mousewheel, false);
    
    const multiplier = 2;
    const center = 2500;
    const interesting = 500;
    
    function mousewheel(event) {
      event.preventDefault();
      let dx = event.deltaX * multiplier;
      if (Math.abs(container.scrollLeft - center) < interesting){
        dx /= 25;
      }
      container.scrollLeft += dx;
      
    }
    body {
      margin: 0;
      height: 100px;
    }
    
    div#container {
      width: 500px;
      height: 100%;
      background-color: green;
      overflow: auto;
    }
    
    div#content {
      width: 5500px; /* Allows scrollLeft up to 5000 */
      height: 100%;
      background-color: red;
      clip-path: polygon(0 0, 100% 0, 100% 100%)
    }
    <div id="container">
      <div id="content"></div>
    </div>
    <pre id="output">0</p>

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-12-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多