
在開發 Mobile Web 時,經常碰到的 iOS 系統上的橡皮筋效果,這個效果搭配上拉刷新,下拉取得資料時,使用者體驗還是挺不錯的,但是實際上,每一個捲軸都擁有這效果,可能會額外造成滑動卡死及不流暢。


對於 ios 原生來說只要一行程式碼,就能關閉彈簧行為,但對 web 來說,則是很麻煩的事。
基於架構現有的手機版架構,所用到 px 都會被postcss工具轉換成 rem ,所以很難算到精準,所以不適合使用 fixed。
全域阻止,還要一個個排外,太麻煩,改動的範圍太大了,且太花時間。
if (this.isiOS) {
inobounce.enable()
}
var isDesktopDebugMode = window.navigator.vendor === 'Google Inc.'
var scrolling = style.getPropertyValue('-webkit-overflow-scrolling') === 'touch' || isDesktopDebugMode

/*! iNoBounce - v0.2.1
* https://github.com/lazd/iNoBounce/
* Copyright (c) 2013 Larry Davis <lazdnet@gmail.com>; Licensed BSD */
(function(global) {
// Stores the Y position where the touch started
var startY = 0
var startX = 0
// Store enabled status
var enabled = false
var supportsPassiveOption = false
try {
var opts = Object.defineProperty({}, 'passive', {
get: function() {
supportsPassiveOption = true
}
})
window.addEventListener('test', null, opts)
} catch (e) {}
var handleTouchmove = function(evt) {
// Get the element that was scrolled upon
var el = evt.target
// Allow zooming
var zoom = window.innerWidth / window.document.documentElement.clientWidth
if (evt.touches.length > 1 || zoom !== 1) {
return
}
// Check all parent elements for scrollability
while (el !== document.body && el !== document) {
// Get some style properties
var style = window.getComputedStyle(el)
if (!style) {
// If we've encountered an element we can't compute the style for, get out
break
}
// Ignore range input element
if (el.nodeName === 'INPUT' && el.getAttribute('type') === 'range') {
return
}
// chrome 在桌面版模擬 ios webkit-overflow-scrolling 屬性沒有作用
var isDesktopDebugMode = window.navigator.vendor === 'Google Inc.'
var scrolling = style.getPropertyValue('-webkit-overflow-scrolling') === 'touch' || isDesktopDebugMode
var overflowY = style.getPropertyValue('overflow-y')
var scrollableY = overflowY === 'auto' || overflowY === 'scroll'
var height = parseInt(style.getPropertyValue('height'), 10)
var width = parseInt(style.getPropertyValue('width'), 10)
// Determine if the element should scroll
var isScrollableY = scrolling && scrollableY
var canScrollY = el.scrollHeight > el.offsetHeight // 能不能滑
var curY = evt.touches ? evt.touches[0].screenY : evt.screenY
if (isScrollableY && canScrollY) {
// Get the current Y position of the touch
// Determine if the user is trying to scroll past the top or bottom
// In this case, the window will bounce, so we have to prevent scrolling completely
var isAtTop = startY <= curY && el.scrollTop === 0
var isAtBottom =
startY >= curY && el.scrollHeight - el.scrollTop === height
// Stop a bounce bug when at the bottom or top of the scrollable element
if (isAtTop || isAtBottom) {
console.log('prevent')
evt.preventDefault()
}
// No need to continue up the DOM, we've done our job
return
}
// 橫向捲動
var overflowX = style.getPropertyValue('overflow-x')
var scrollableX = overflowX === 'auto' || overflowX === 'scroll'
var isScrollableX = scrolling && scrollableX
var canScrollX = el.scrollWidth > el.offsetWidth
if (isScrollableX && canScrollX) {
// debugger
// Get the current X position of the touch
var curX = evt.touches ? evt.touches[0].screenX : evt.screenX
// Determine if the user is trying to scroll past the top or bottom
// In this case, the window will bounce, so we have to prevent scrolling completely
var isAtLeft = startX <= curX && el.scrollLeft === 0
var isAtRight =
startX >= curX && el.scrollWidth - el.scrollLeft === width
// Stop a bounce bug when at the bottom or top of the scrollable element
if (isAtLeft || isAtRight) {
evt.preventDefault()
}
// No need to continue up the DOM, we've done our job
return
}
// Test the next parent
el = el.parentNode
}
// Stop the bouncing -- no parents are scrollable
evt.preventDefault()
}
var handleTouchstart = function(evt) {
// Store the first Y position of the touch
startY = evt.touches ? evt.touches[0].screenY : evt.screenY
startX = evt.touches ? evt.touches[0].screenX : evt.screenX
}
var enable = function() {
// Listen to a couple key touch events
window.addEventListener(
'touchstart',
handleTouchstart,
supportsPassiveOption ? { passive: false } : false
)
window.addEventListener(
'touchmove',
handleTouchmove,
supportsPassiveOption ? { passive: false } : false
)
enabled = true
}
var disable = function() {
// Stop listening
window.removeEventListener('touchstart', handleTouchstart, false)
window.removeEventListener('touchmove', handleTouchmove, false)
enabled = false
}
var isEnabled = function() {
return enabled
}
// Enable by default if the browser supports -webkit-overflow-scrolling
// Test this by setting the property with JavaScript on an element that exists in the DOM
// Then, see if the property is reflected in the computed style
var testDiv = document.createElement('div')
document.documentElement.appendChild(testDiv)
testDiv.style.WebkitOverflowScrolling = 'touch'
var scrollSupport =
'getComputedStyle' in window &&
window.getComputedStyle(testDiv)['-webkit-overflow-scrolling'] === 'touch'
document.documentElement.removeChild(testDiv)
if (scrollSupport) {
enable()
}
// A module to support enabling/disabling iNoBounce
var iNoBounce = {
enable: enable,
disable: disable,
isEnabled: isEnabled
}
if (typeof module !== 'undefined' && module.exports) {
// Node.js Support
module.exports = iNoBounce
}
if (typeof global.define === 'function') {
// AMD Support
(function(define) {
define('iNoBounce', [], function() {
return iNoBounce
})
})(global.define)
} else {
// Browser support
global.iNoBounce = iNoBounce
}
})(this)
在 Web 看起來是無法完美避免橡皮筋行為,比較好的做法是改 Layout,捲到最上時用 CSS Fixed 住,回彈時,上面有東西擋住 滾動就沒這麼怪。
inobounce js只能解決
暫時無法解決的問題