Ios pit under UIWebView

Recently, I made a requirement to make the effect of top suction. Under android and IOS systems of higher versions, the effect of top suction can be perfectly realized. However, in IOS of lower versions, I encountered a pit.

Google has analyzed the cause, and there are two reasons for this.

1. The Scroll event in UIWebView will only be triggered when scrolling stops

If you are listening for scrolling using addEventListener, then unfortunately you have been caught. Binding the scrolling event in this way, as the title suggests, will only trigger once when scrolling stops.

But if you use window.onscroll to listen for scroll, you can trigger the Scroll event while scrolling. Isn’t that amazing?

There is also said online that using TouchMove to monitor, but also can trigger the event when scrolling, but TouchMove has two disadvantages:

  • It has a low trigger frequency, meaning it has to roll a certain distance to trigger
  • It’s inertial scrolling, that is, it simulates inertial scrolling for a certain distance when our finger goes away, and neither Scroll nor touchmove is triggered at that point.

However, I changed onScroll to listen for scroll, but I still can’t update the top element in time. It’s the same as using addEventListener to listen for Scroll. This leads to the second reason for this phenomenon.

2. Under UIWebView, all asynchronous scroll operations will be blocked

The reason for this is probably the same as the first one. IOS wants to do some optimization to avoid repetitive operations, which is the same as our idea of function throttling. My technical stack uses VUE, and as we know, VUE updates the DOM asynchronously, so my view update operation in OnScroll through VUE will be blocked by ios and will be executed only after scrolling stops.

By the way, if your scroll handler is optimized with anti-shake, the effect is the same, because anti-shake is implemented by setTimeout, and setTimeout is also an asynchronous operation, which is blocked by IOS.

The solution

If the first cause is window.onscroll, use window.onscroll to listen for scrolling. If the second cause is window.onscroll, avoid using asynchronous operations in scroll events. If you use vue or React frameworks, they update the DOM asynchronously.

Plan a

Optionally use normal and native JS to manipulate the DOM update view, depending on whether it is a UIWebView or not

if (isUIWebView) {
    window.onscroll = function() {// use native js to manipulate dom}}else{/ / normal situation, the use of stabilization, vue | react to operate dom window. The addEventListener ('scroll', this.scrollHandler)
}
Copy the code

Scheme 2

Use third-party scrolling plug-ins, such as Iscroll, to simulate scrolling.

Other pit

  • A problem with sinking an OS element after inline-block is set

  • In ios UIWebView, the pageYOffset property is invalid as a compatible way to get the scroll distance
function getScrollTop(el) {
  if(! el) {return document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop;
  }
  return el.scrollTop;
}
Copy the code