macos 如何检测/禁用 Mac Safari 中的惯性滚动?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4339196/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to detect/disable inertial scrolling in Mac Safari?
提问by mherf
Is there a way to disable or detect that wheel events are from the "inertia" setting on a Mac?
有没有办法禁用或检测滚轮事件来自 Mac 上的“惯性”设置?
I'd like to be able to tell the difference between real events and the others...or disable that kind of scrolling for a particular page.
我希望能够分辨真实事件和其他事件之间的区别……或者禁用特定页面的那种滚动。
回答by OldDrunkenSailor
Yes and no.
是和否。
You can use touchdown/up, and scroll as events to look for the page moving about but those won't trigger if the OS is doing an inertial scroll. Fun, right?
您可以使用触地/向上,并作为事件滚动来查找移动的页面,但如果操作系统正在执行惯性滚动,则不会触发这些事件。好玩吧?
One thing that you can continually detect, however, is window.pageYOffset. That value will keep changing while an inertial scroll is happening but won't throw an event. So you can come up with a set of timers to keep checking for an inertial scroll and keep running itself until the page has stopped moving.
但是,您可以不断检测到的一件事是 window.pageYOffset。当惯性滚动发生时,该值将不断变化,但不会引发事件。所以你可以想出一组计时器来不断检查惯性滚动并继续运行直到页面停止移动。
Tricky stuff, but it should work.
棘手的东西,但它应该工作。
回答by kodisha
Oh how is this issue killing me :/
哦,这个问题如何杀死我:/
I'm in the process of creating "endless" scrolling large file viewer.
我正在创建“无限”滚动大文件查看器。
To make situation worse, this editor is embedded in page that has its own scroll bar, because its bigger than one screen.
更糟糕的是,这个编辑器嵌入在有自己滚动条的页面中,因为它比一个屏幕大。
U use overflow-x scroll for horizontal scroll, but for vertical scroll i need current line highlighter (as seen in most modern IDEs) so i'm using jquery mousewheel plugin, and scrolling moving content for line height up or down.
你使用溢出-x 滚动进行水平滚动,但对于垂直滚动,我需要当前行高亮显示(如在大多数现代 IDE 中所见),所以我使用 jquery 鼠标滚轮插件,并向上或向下滚动移动内容的行高。
It works perfectly on ubuntu/chrome but on MacOS Lion/Chrome sometimes, and just sometimes, when you scroll, it doesn't prevent default scroll on the editor element, and event propagates "up" and page it self starts to scroll.
它在 ubuntu/chrome 上完美运行,但有时在 MacOS Lion/Chrome 上运行,只是有时,当您滚动时,它不会阻止编辑器元素上的默认滚动,并且事件“向上”传播并且页面本身开始滚动。
I cant even describe how much annoying that is.
我什至无法描述那有多烦人。
As for inertial scroll it self, i successfully reduced it with two timers
至于惯性滚动它自己,我成功地用两个计时器减少了它
var self = this;
// mouse wheel events
$('#editorWrapper').mousewheel(function (event, delta, deltax, deltay) {
self._thisScroll = new Date().getTime();
//
//this is entirely because of Inertial scrolling feature on mac os :(
//
if((self._thisScroll - self._lastScroll) > 5){
//
//
// NOW i do actual moving of content
//
//
self._lastScroll = new Date().getTime();
}
5ms is value i found to have most natural feel on my MacBook Pro, and you have to scroll mouse wheel really fast to catch one of those..
我发现 5 毫秒是我在 MacBook Pro 上感觉最自然的值,你必须非常快速地滚动鼠标滚轮才能抓住其中之一。
Even still, sometimes on Mac listener on mac wrapper doesn't prevent default, and page scrolls down.
即便如此,有时在 Mac 包装器上的 Mac 侦听器上也不会阻止默认设置,并且页面会向下滚动。
回答by Nareshkumar Rao
Well, (I might be wrong), I think that the "inertia" settings on the Mac are all computed by the system itself, the browser, or any program for that matter would just think that the user is scrolling quickly, rather than slowing down.
嗯,(我可能是错的),我认为 Mac 上的“惯性”设置都是由系统本身、浏览器或任何与此相关的程序计算出来的,只会认为用户正在快速滚动,而不是减慢速度向下。
回答by Yuriy Polezhayev
I'm not sure about other browsers, but the following event fires during inertial scroll on my Chrome, FF, Safari (mac):
我不确定其他浏览器,但在我的 Chrome、FF、Safari (mac) 上的惯性滚动期间会触发以下事件:
var mousewheelevt=(/Firefox/i.test(navigator.userAgent))? "DOMMouseScroll" : "mousewheel";
function scrollEE (e) {
console.log(e);
}
window.addEventListener(mousewheelevt, scrollEE, false);
回答by Christiaan Westerbeek
There's a library that solves this problem.
有一个库可以解决这个问题。
https://github.com/d4nyll/lethargy
https://github.com/d4nyll/lethargy
After installing it, use it like this:
安装后,像这样使用它:
var lethargy = new Lethargy();
$(window).bind('mousewheel DOMMouseScroll wheel MozMousePixelScroll', function(e){
if(lethargy.check(e) === false) {
console.log('stopping zoom event from inertia')
e.preventDefault()
e.stopPropagation();
}
console.log('Continue with zoom event from intent')
});
回答by kragovip
I found a solution that works really well for this. Below is some pasted code from my project. It basically comes down to this logic:
我找到了一个非常适用于此的解决方案。以下是我项目中的一些粘贴代码。它基本上归结为这个逻辑:
A scroll event is from a human when ANY ONE of these conditions are true:
当以下任何一个条件为真时,滚动事件来自人类:
- The direction is the other way around than the last one
- More than 50 milliseconds passed since the last scroll event (picked 100ms to be sure)
- The delta value is at least as high as the previous one
- 方向与上一个相反
- 自上次滚动事件以来已过去 50 多毫秒(确定为 100 毫秒)
- delta 值至少和前一个一样高
Since Mac spams scroll events with descreasing delta's to the browser every 20ms when inertial scrolling is enabled, this is a pretty failsafe way. I've never had it fail on me at least. Just checking the time since the last scroll won't work because a user won't be able to scroll again if the "virtual freewheel" is still running even though they haven't scrolled for 3 seconds.
由于 Mac 垃圾邮件会在启用惯性滚动时每 20 毫秒将事件滚动到浏览器的 delta 递减一次,因此这是一种非常安全的方式。至少我从来没有失败过。仅检查自上次滚动以来的时间是行不通的,因为如果“虚拟飞轮”仍在运行,即使用户没有滚动 3 秒,也将无法再次滚动。
this.minScrollWheelInterval = 100; // minimum milliseconds between scrolls
this.animSpeed = 300;
this.lastScrollWheelTimestamp = 0;
this.lastScrollWheelDelta = 0;
this.animating = false;
document.addEventListener('wheel',
(e) => {
const now = Date.now();
const rapidSuccession = now - this.lastScrollWheelTimestamp < this.minScrollWheelInterval;
const otherDirection = (this.lastScrollWheelDelta > 0) !== (e.deltaY > 0);
const speedDecrease = Math.abs(e.deltaY) < Math.abs(this.lastScrollWheelDelta);
const isHuman = otherDirection || !rapidSuccession || !speedDecrease;
if (isHuman && !this.animating) {
this.animating = true; // current animation starting: future animations blocked
$('.something').stop().animate( // perform some animation like moving to the next/previous page
{property: value},
this.animSpeed,
() => {this.animating = false} // animation finished: ready for next animation
)
}
this.lastScrollWheelTimestamp = now;
this.lastScrollWheelDelta = e.deltaY;
},
{passive: true}
);
There's one caveat by the way: Mac also has accelerationon the scrolling, i.e.: at first, the delta value is higher for each successive event. It seems like this does not last more than 100ms or so though. So if whatever action/animation you are firing as a result of the scroll event lasts at least 100ms and blocks all other actions/animations in the meantime, this is never a problem.
顺便说一下,有一个警告:Mac 也有滚动加速,即:首先,每个连续事件的增量值都更高。不过,这似乎不会持续超过 100 毫秒左右。因此,如果您因滚动事件而触发的任何动作/动画持续至少 100 毫秒并在此期间阻止所有其他动作/动画,那么这绝不是问题。
回答by Oliver
I had a big problem with an object animating based on scroll position after the scroll had completed, and the inertial scroll was really messing me around. I ended up calculating the velocity to determine how long the inertial scroll would last and used that to wait before animating.
滚动完成后,基于滚动位置的对象动画有一个大问题,惯性滚动真的让我感到困惑。我最终计算了速度以确定惯性滚动将持续多长时间,并在动画之前使用它来等待。
var currentY = 0;
var previousY = 0;
var lastKnownVelocity = 0;
var velocityRating = 1;
function calculateVelocity() {
previousY = currentY;
currentY = $('#content').scrollTop();
lastKnownVelocity = previousY - currentY;
if (lastKnownVelocity > 20 || lastKnownVelocity < -20) {
velocityRating = 5;
} else {
velocityRating = 1;
}
}
$('#content').scroll(function () {
// get velocity while scrolling...
calculateVelocity();
// wait until finished scrolling...
clearTimeout($.data(this, 'scrollTimer'));
$.data(this, 'scrollTimer', setTimeout(function() {
// do your animation
$('#content').animate({scrollTop: snapPoint}, 300);
}, 300*velocityRating)); // short or long duration...
});