ChatGPT解决这个技术问题 Extra ChatGPT

javascript scroll event for iPhone/iPad?

I can't seem to capture the scroll event on an iPad. None of these work, what I am doing wrong?

window.onscroll=myFunction;

document.onscroll=myFunction;

window.attachEvent("scroll",myFunction,false);

document.attachEvent("scroll",myFunction,false);

They all work even on Safari 3 on Windows. Ironically, EVERY browser on the PC supports window.onload= if you don't mind clobbering existing events. But no go on iPad.


C
Cœur

The iPhoneOS does capture onscroll events, except not the way you may expect.

One-finger panning doesn’t generate any events until the user stops panning—an onscroll event is generated when the page stops moving and redraws—as shown in Figure 6-1.

Similarly, scroll with 2 fingers fires onscroll only after you've stopped scrolling.

The usual way of installing the handler works e.g.

window.addEventListener('scroll', function() { alert("Scrolled"); });
// or
$(window).scroll(function() { alert("Scrolled"); });
// or
window.onscroll = function() { alert("Scrolled"); };
// etc 

(See also https://developer.apple.com/library/content/documentation/AppleApplications/Reference/SafariWebContent/HandlingEvents/HandlingEvents.html)


Thanks, that forced me to look further at the problem. The real answer was detecting the top of the viewport on the iphone/ipad only works with window.pageYOffset and not document.body.scrollTop||document.documentElement.scrollTop like every other browser/hardware in existence.
@ck_ Unfortunatelly on IPAD window.pageYOffset does not get updated in the deceleration phase, but only when scroll finishes.
It is bad practice to directly overwrite window.onscroll. Adding an event listener would be better. Use window.addEventListener('scroll', function (){ alert('scrolled!'); });
ehm .. actually, window.onscroll is firing on my ipad all the time now, while panning, and after panning, while decelerating. did something change ?
Safari (and maybe others) changed to using WKWebView with iOS 8. Chrome and Cordova still use UIWebView, so they still exhibit the issue with continuous scroll events not being issued. There's a WKWebView plug-in for Cordova though.
G
George Filippakos

For iOS you need to use the touchmove event as well as the scroll event like this:

document.addEventListener("touchmove", ScrollStart, false);
document.addEventListener("scroll", Scroll, false);

function ScrollStart() {
    //start of scroll event for iOS
}

function Scroll() {
    //end of scroll event for iOS
    //and
    //start/end of scroll event for other browsers
}

This event is only fired when the user is actively scrolling it is not fired during the deceleration phase of momentum scrolling.
i changed the code to include the end scroll detection code for iOS
You might also want to add a listener for "touchend" which will act similar to scroll on desktop.
Note that this does not provide access to the during scroll phase
it's been three years. I can't get a realtime update of scroll position during deceleration. how am I supposed to write my maps-like app?????
D
Dave Mackintosh

Sorry for adding another answer to an old post but I usually get a scroll event very well by using this code (it works at least on 6.1)

element.addEventListener('scroll', function() {
    console.log(this.scrollTop);
});

// This is the magic, this gives me "live" scroll events
element.addEventListener('gesturechange', function() {});

And that works for me. Only thing it doesn't do is give a scroll event for the deceleration of the scroll (Once the deceleration is complete you get a final scroll event, do as you will with it.) but if you disable inertia with css by doing this

-webkit-overflow-scrolling: none;

You don't get inertia on your elements, for the body though you might have to do the classic

document.addEventListener('touchmove', function(e) {e.preventDefault();}, true);

Why downvote a valid answer and not leave a comment explaining the problem with it?
because downvoting is easy and quick. :/
An answer is ALWAYS "valid" according to its author...Nobody posts a knowingly invalid answer. But yes, they should have explained why they downvoted.
gesturechange events is non standard and only supported by Safari: developer.mozilla.org/en-US/docs/Web/Events/gesturechange
M
Melinda Weathers

I was able to get a great solution to this problem with iScroll, with the feel of momentum scrolling and everything https://github.com/cubiq/iscroll The github doc is great, and I mostly followed it. Here's the details of my implementation.

HTML: I wrapped the scrollable area of my content in some divs that iScroll can use:

<div id="wrapper">
  <div id="scroller">
    ... my scrollable content
  </div>
</div>

CSS: I used the Modernizr class for "touch" to target my style changes only to touch devices (because I only instantiated iScroll on touch).

.touch #wrapper {
  position: absolute;
  z-index: 1;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  overflow: hidden;
}
.touch #scroller {
  position: absolute;
  z-index: 1;
  width: 100%;
}

JS: I included iscroll-probe.js from the iScroll download, and then initialized the scroller as below, where updatePosition is my function that reacts to the new scroll position.

# coffeescript
if Modernizr.touch
  myScroller = new IScroll('#wrapper', probeType: 3)
  myScroller.on 'scroll', updatePosition
  myScroller.on 'scrollEnd', updatePosition

You have to use myScroller to get the current position now, instead of looking at the scroll offset. Here is a function taken from http://markdalgleish.com/presentations/embracingtouch/ (a super helpful article, but a little out of date now)

function getScroll(elem, iscroll) {   
  var x, y;

  if (Modernizr.touch && iscroll) {
    x = iscroll.x * -1;
    y = iscroll.y * -1;   
  } else {
    x = elem.scrollTop;
    y = elem.scrollLeft;   
  }

  return {x: x, y: y}; 
}

The only other gotcha was occasionally I would lose part of my page that I was trying to scroll to, and it would refuse to scroll. I had to add in some calls to myScroller.refresh() whenever I changed the contents of the #wrapper, and that solved the problem.

EDIT: Another gotcha was that iScroll eats all the "click" events. I turned on the option to have iScroll emit a "tap" event and handled those instead of "click" events. Thankfully I didn't need much clicking in the scroll area, so this wasn't a big deal.


M
Matthias Bohlen

Since iOS 8 came out, this problem does not exist any more. The scroll event is now fired smoothly in iOS Safari as well.

So, if you register the scroll event handler and check window.pageYOffset inside that event handler, everything works just fine.


It does exists yet in some use cases like using Cordova. developer.telerik.com/featured/…
My experience is that this still remains a problem with current iOS devices in 2019.
Still experiencing this problem with iOS devices running iOS 15