简体   繁体   中英

In iOS 7 Safari, how do you differentiate popstate events via edge swipe vs. the back/fwd buttons?

In iOS 7 Safari there are now two ways to navigate back/forward -- using the traditional back/forward button arrows at the bottom or by swiping from the edge of the screen. I'm using an animation to transition between pages in my ajax app, but I don't want to fire that transition if users are navigating via the edge swipe, because that is an animation itself.

However, the popstate event objects appear to be identical for both types of navigation -- is there any way to differentiate between these two types of user navigations so we can respond accordingly?

UPDATE: I was able to use (what appears to be) a bug in iOS7 Safari to detect correctly the edge swipe vs. back button tap. The bug is that the touchend event is not triggered (until the next touch event) when using the edge swipe (but touchstart and touchmove are). So I set a shouldAnimate flag and disable it on touchmove -- then if the flag is disabled and the popstate occurs, I know it's an edge swipe.

It's correct 99% of the time -- the only time where it could potentially fail is when a user edge-swipes partially and but then lets go and lets the current page snap back into place (at which point my flag would still be disabled) and then taps the back button (which fires no touch events). To handle that last [edge] case I set a timer on touchmove to re-enable the flag after 50ms.

Yes it's "dirty" but for now it gets me what I want in almost every case so I'm ok with it -- until Apple fixes the bug, but hopefully they'll also provide an indicator in the popstate event object that tells us what kind of navigation it is.

简短而悲伤的答案:不会。这种后退/前进滑动不会传播到实际页面,而是发生在操作系统级别。

You can track edge drag navigation by monitoring the touch events. If the user starts dragging within a certain threshold of the edge of their screen, it will trigger an edge drag navigation transition. I wrote an extended explanation of how to monitor and act on this using React code here: https://gist.github.com/MartijnHols/709965559cbdb6b241c12e5866941e69 , but the essential part can be achieved in regular JavaScript (albeit the example code is TypeScript, but you can just strip the types).

const IOS_EDGE_DRAG_NAVIGATION_THRESHOLD = 25

let timer: ReturnType<typeof setTimeout>
const handleTouchStart = (e: TouchEvent) => {
  if (
    e.touches[0].pageX > IOS_EDGE_DRAG_NAVIGATION_THRESHOLD &&
    e.touches[0].pageX <
      window.innerWidth - IOS_EDGE_DRAG_NAVIGATION_THRESHOLD
  ) {
    return
  }

  isEdgeDragNavigationVar(true)
  if (timer) {
    clearTimeout(timer)
  }
}
const handleTouchEnd = () => {
  timer = setTimeout(() => isEdgeDragNavigationVar(false), 200)
}

document.addEventListener('touchstart', handleTouchStart)
document.addEventListener('touchend', handleTouchEnd)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM