UNPKG

overscroll

Version:
303 lines (264 loc) 7.17 kB
import is from 'whatitis'; import actions from './actions'; import domUtils from './utils/dom'; import domStates from './domStates'; import animations from './animations'; import getWindow from './utils/dom/getWindow'; import getDocument from './utils/dom/getDocument'; import { handleDestroy, handleScroll, handleBeforeScroll, handleAfterScroll, handleInit } from './handlers'; const X = 'x'; const Y = 'y'; const XY = 'xy'; const xreg = /x/i; const yreg = /y/i; const OVERSCROLL = 'OverScroll'; const OVERSCROLLX = 'OverScrollX'; const OVERSCROLLY = 'OverScrollY'; const BUBBLE = 'bubble'; const NOBUBBLE = 'noBubble'; function hasX( axis ) { return xreg.test( axis ); } function hasY( axis ) { return yreg.test( axis ); } function hasXY( axis ) { return hasX( axis ) && hasY( axis ); } function getAxis( axis = XY ) { if ( hasXY( axis )) { return XY; } else if ( hasX( axis )) { return X; } return Y; } const getScrollByAxis = ({ target, axis, win, html, body, isPageScroll }) => () => { // CSS1Compat 标准模式 BackCompat 混杂模式 // const isCSS1Compat = doc.compatMode === 'CSS1Compat'; const scrollX = () => { return !isPageScroll ? target.scrollLeft : is.Defined( win.pageXOffset ) ? win.pageXOffset : Math.max( html.scrollLeft, body.scrollLeft ); }; const scrollY = () => { return !isPageScroll ? target.scrollTop : is.Defined( win.pageYOffset ) ? win.pageYOffset : Math.max( html.scrollTop, body.scrollTop ); }; if ( hasXY( axis )) { return { top: scrollY(), left: scrollX() }; } else if ( hasX( axis )) { return { top: 0, left: scrollX() }; } return { top: scrollY(), left: 0 }; }; const defaultOptions = { axis: XY, prefix: OVERSCROLL, thumbMiniSize: 20, // show: true, // showX: true, // showY: true, target: null, watchInterval: 100, watch: null, onInit: null, onScroll: null, onBeforeScroll: null, onAfterScroll: null, onDestroy: null, // getContainer: null, isPageScroll: false, // 判断是否是页面滚动 mode: 'scroll', // 'section' anchors: null, switchScale: [ 0.2, 0.2 ], // [往上拉的距离比例,往下拉的距离比例] position: [ 0, 0 ], bubble: true, // 让父级的滚动可以触发 dragable: true, // pointerType === 'mouse' 的开关 touchable: true // pointerType === 'touch' 的开关 }; function getOptions({ axis, prefix, // show, // showX, // showY, target, watchInterval, watch, onInit, onScroll, onBeforeScroll, onAfterScroll, onDestroy, // getContainer, mode, anchors, switchScale, position, bubble, dragable, touchable } = {}) { const options = Object.assign({}, defaultOptions ); const doc = getDocument( target ); const win = getWindow( doc ); const body = doc.body; const html = doc.documentElement; // 滚动容器 if ( is.Undefined( target ) || [ html, body ].includes( target )) { options.target = doc.scrollingElement || body; options.isPageScroll = true; } else { options.target = target; } // 元素装载容器 // if ( target === html ) { // // options.container = options.target === html ? body : options.target; // options.target = body; // } else { // options.target = target; // } // container => containerX containerY // if ( is.Function( getContainer )) { // const container = getContainer(); // if ( is.Element( container )) { // options.containerX = container; // options.containerY = container; // } else { // const { x, y, X, Y } = container; // options.containerX = x || X; // options.containerY = y || Y || options.containerX; // } // } else { // options.containerX = options.container; // options.containerY = options.containerX; // } // 滚动条 计算 // axis => scrollX scrollY options.axis = getAxis( axis ); options.scrollX = hasX( options.axis ); options.scrollY = hasY( options.axis ); // 滚动条 显示/隐藏 // show => showX showY // options.show = show !== false; // options.showX = options.show && showX !== false; // options.showY = options.show && showY !== false; // 样式前缀 prefix if ( is.String( prefix )) { options.prefix = prefix; } // 事件 if ( is.Function( onInit )) { options.onInit = onInit; } // onScroll( scrollTop, scrollLeft ) if ( is.Function( onScroll )) { options.onScroll = onScroll; } if ( is.Function( onBeforeScroll )) { options.onBeforeScroll = onBeforeScroll; } if ( is.Function( onAfterScroll )) { options.onAfterScroll = onAfterScroll; } if ( is.Function( onDestroy )) { options.onDestroy = onDestroy; } if ( is.Function( watch )) { options.watch = watch; if ( is.Number( watchInterval ) && watchInterval > 50 ) { options.watchInterval = watchInterval; } } if ( is.Array( position ) && position.every( is.Number )) { options.position = position; } if ( mode === 'section' ) { options.mode = mode; options.axis = hasY( options.axis ) ? Y : X; options.scrollX = options.axis === X; options.scrollY = options.axis === Y; options.position = is.Number( position ) ? position : 1; if ( is.Array( anchors ) && anchors.every( is.Element )) { options.anchors = anchors; } else { options.anchors = Array.prototype.slice.call( target.children ); } if ( is.String( switchScale ) && /^\d*$/.test( switchScale )) { switchScale = [ parseFloat( switchScale ), parseFloat( switchScale ) ]; } if ( is.Number( switchScale )) { switchScale = [ switchScale, switchScale ]; } if ( is.Array( switchScale ) && anchors.every(( num ) => is.Number( num ) && num <= 1 && num >= 0 ) ) { options.switchScale = [].concat( switchScale ); } } // 设置当前滚动区间是否冒泡事件 if ( bubble === false ) { options.bubble = bubble; } // 鼠标拖动开关 if ( dragable === false ) { options.dragable = dragable; } // 触摸开关 if ( touchable === false ) { options.touchable = touchable; } return Object.assign( options, { body, html, doc, win }); } export default ( options ) => { const overscroll = { scrollTop: 0, scrollLeft: 0, scrollHeight: 0, scrollWidth: 0, clientHeight: 0, clientWidth: 0, section: 1, scrolling: false }; const scope = { X, Y, XY, xreg, yreg, hasX, hasY, hasXY, OVERSCROLL, OVERSCROLLX, OVERSCROLLY, BUBBLE, NOBUBBLE, overscroll }; Object.assign( scope, getOptions( options )); Object.assign( scope, domUtils( scope ), { getScroll: getScrollByAxis( scope ), handleDestroy: handleDestroy( scope ), handleBeforeScroll: handleBeforeScroll( scope ), handleAfterScroll: handleAfterScroll( scope ), handleScroll: handleScroll( scope ), handleInit: handleInit( scope ) }); Object.assign( scope, domStates( scope )); Object.assign( scope, actions( scope )); Object.assign( scope, animations( scope )); return scope; };