如何在网络应用中停止惯性滚动

问题描述

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

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

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

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

运行代码段,然后使用鼠标垫(或触摸屏)将可滚动元素向左滑动。你会看到:

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

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

我的问题是:在滚动到达某个点后,有没有办法完全停止发出 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%)
}

解决方法

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

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

考虑到这些因素,您可以轻松建立自己的行为。我简化了代码以强调策​​略。简而言之,您设置图片的 center 和围绕该中心的 interesting 区域。您始终阻止默认行为(劫持事件)。如果 scrollLeft 属性在 interesting 周围的 center 区域之外,则根据 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>

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...