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



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

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

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

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

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

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

但是,如果向左滚动超过2500,然后尝试向右滑动,则不会发生任何事情。第一个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 + "sn" + 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>

我认为您无法阻止浏览器发出事件。这就是为什么必须使用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>

最新更新