如何停止 Web 应用程序中的惯性滚动
How to stop inertial scrolling in a web app
我正在为年轻人 children 创建一个网络应用程序,他们可以在其中水平滚动非常宽的图片。年轻人 children 可能会疯狂地滑动触摸屏。我想允许惯性滚动(因为它很有趣)但限制它以便 child 用户不会快速向后和向前滚动到最后,错过中间的所有好东西。
在惯性滚动期间,会生成 mousewheel
事件。我曾希望在此事件中使用 event.preventDefault()
,以便在特定点停止惯性滚动。但是,似乎如果您在特定操作的第一个 mousewheel
事件中不 运行 preventDefault()
,则以下事件中的 none 将被阻止。
下面的代码片段提供了一个演示。它包含一个可以滚动直到其 scrollLeft
值达到 5000 的元素。JavaScript 包含一个 mousewheel
事件侦听器,当 [=17= 的值达到时显式调用 event.preventDefault()
] 大于 2500。
我曾希望这会中途停止惯性滚动。但是没有。
运行 片段,然后使用鼠标垫(或触摸屏)向左滑动可滚动元素。你会看到:
- 如果您提供足够的惯性,该元素将一直滚动到左侧。对
event.preventDefault()
的条件调用无效。
mousewheel
事件将持续发出最多 5 秒(取决于您滑动所用的能量)。即使在元素完全向左滚动后,它们也会继续发射。
但是,如果您向左滚动超过 2500,然后尝试向右滑动,则不会发生任何事情。 first mousewheel
事件的默认操作被阻止,因此惯性滚动永远不会启动。
我的问题是:有没有办法在滚动到达某个点后完全停止发出 mousewheel
事件?奖励问题:有没有办法确定特定滑动手势中有多少惯性?
我有一个限制 scrollLeft
值的变通方法,但这意味着 child 将无法再次滑动,直到发出最后一个 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>
我认为您无法阻止浏览器发出事件。这就是为什么必须使用 preventDefault
的原因。因此,为了回答您的问题,
- 没有。但是,您可以劫持该事件并使用它来满足您的预期行为。
- 是的。
mousewheel
事件有一个 wheelDelta
值,惯性越大,该值越大。请务必注意 mousewheel
已弃用。您应该使用 wheel
事件。在这种情况下,该事件将具有您可以使用的 deltaX
和 deltaY
值。
考虑到这些因素,您可以轻松地建立自己的行为。我简化了代码以强调该策略。简而言之,您设置图片的 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>
我正在为年轻人 children 创建一个网络应用程序,他们可以在其中水平滚动非常宽的图片。年轻人 children 可能会疯狂地滑动触摸屏。我想允许惯性滚动(因为它很有趣)但限制它以便 child 用户不会快速向后和向前滚动到最后,错过中间的所有好东西。
在惯性滚动期间,会生成 mousewheel
事件。我曾希望在此事件中使用 event.preventDefault()
,以便在特定点停止惯性滚动。但是,似乎如果您在特定操作的第一个 mousewheel
事件中不 运行 preventDefault()
,则以下事件中的 none 将被阻止。
下面的代码片段提供了一个演示。它包含一个可以滚动直到其 scrollLeft
值达到 5000 的元素。JavaScript 包含一个 mousewheel
事件侦听器,当 [=17= 的值达到时显式调用 event.preventDefault()
] 大于 2500。
我曾希望这会中途停止惯性滚动。但是没有。
运行 片段,然后使用鼠标垫(或触摸屏)向左滑动可滚动元素。你会看到:
- 如果您提供足够的惯性,该元素将一直滚动到左侧。对
event.preventDefault()
的条件调用无效。 mousewheel
事件将持续发出最多 5 秒(取决于您滑动所用的能量)。即使在元素完全向左滚动后,它们也会继续发射。
但是,如果您向左滚动超过 2500,然后尝试向右滑动,则不会发生任何事情。 first mousewheel
事件的默认操作被阻止,因此惯性滚动永远不会启动。
我的问题是:有没有办法在滚动到达某个点后完全停止发出 mousewheel
事件?奖励问题:有没有办法确定特定滑动手势中有多少惯性?
我有一个限制 scrollLeft
值的变通方法,但这意味着 child 将无法再次滑动,直到发出最后一个 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>
我认为您无法阻止浏览器发出事件。这就是为什么必须使用 preventDefault
的原因。因此,为了回答您的问题,
- 没有。但是,您可以劫持该事件并使用它来满足您的预期行为。
- 是的。
mousewheel
事件有一个wheelDelta
值,惯性越大,该值越大。请务必注意mousewheel
已弃用。您应该使用wheel
事件。在这种情况下,该事件将具有您可以使用的deltaX
和deltaY
值。
考虑到这些因素,您可以轻松地建立自己的行为。我简化了代码以强调该策略。简而言之,您设置图片的 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>