You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
388 lines
13 KiB
388 lines
13 KiB
/*!
|
|
* better-scroll / mouse-wheel
|
|
* (c) 2016-2020 ustbhuangyi
|
|
* Released under the MIT License.
|
|
*/
|
|
function warn(msg) {
|
|
console.error("[BScroll warn]: " + msg);
|
|
}
|
|
|
|
// ssr support
|
|
var inBrowser = typeof window !== 'undefined';
|
|
var ua = inBrowser && navigator.userAgent.toLowerCase();
|
|
var isWeChatDevTools = !!(ua && /wechatdevtools/.test(ua));
|
|
var isAndroid = ua && ua.indexOf('android') > 0;
|
|
/* istanbul ignore next */
|
|
var isIOSBadVersion = (function () {
|
|
if (typeof ua === 'string') {
|
|
var regex = /os (\d\d?_\d(_\d)?)/;
|
|
var matches = regex.exec(ua);
|
|
if (!matches)
|
|
return false;
|
|
var parts = matches[1].split('_').map(function (item) {
|
|
return parseInt(item, 10);
|
|
});
|
|
// ios version >= 13.4 issue 982
|
|
return !!(parts[0] >= 13 && parts[1] >= 4);
|
|
}
|
|
return false;
|
|
})();
|
|
|
|
var extend = function (target, source) {
|
|
for (var key in source) {
|
|
target[key] = source[key];
|
|
}
|
|
return target;
|
|
};
|
|
|
|
var elementStyle = (inBrowser &&
|
|
document.createElement('div').style);
|
|
var vendor = (function () {
|
|
/* istanbul ignore if */
|
|
if (!inBrowser) {
|
|
return false;
|
|
}
|
|
var transformNames = [
|
|
{
|
|
key: 'standard',
|
|
value: 'transform',
|
|
},
|
|
{
|
|
key: 'webkit',
|
|
value: 'webkitTransform',
|
|
},
|
|
{
|
|
key: 'Moz',
|
|
value: 'MozTransform',
|
|
},
|
|
{
|
|
key: 'O',
|
|
value: 'OTransform',
|
|
},
|
|
{
|
|
key: 'ms',
|
|
value: 'msTransform',
|
|
},
|
|
];
|
|
for (var _i = 0, transformNames_1 = transformNames; _i < transformNames_1.length; _i++) {
|
|
var obj = transformNames_1[_i];
|
|
if (elementStyle[obj.value] !== undefined) {
|
|
return obj.key;
|
|
}
|
|
}
|
|
/* istanbul ignore next */
|
|
return false;
|
|
})();
|
|
/* istanbul ignore next */
|
|
function prefixStyle(style) {
|
|
if (vendor === false) {
|
|
return style;
|
|
}
|
|
if (vendor === 'standard') {
|
|
if (style === 'transitionEnd') {
|
|
return 'transitionend';
|
|
}
|
|
return style;
|
|
}
|
|
return vendor + style.charAt(0).toUpperCase() + style.substr(1);
|
|
}
|
|
function addEvent(el, type, fn, capture) {
|
|
el.addEventListener(type, fn, {
|
|
passive: false,
|
|
capture: !!capture,
|
|
});
|
|
}
|
|
function removeEvent(el, type, fn, capture) {
|
|
el.removeEventListener(type, fn, {
|
|
capture: !!capture,
|
|
});
|
|
}
|
|
var cssVendor = vendor && vendor !== 'standard' ? '-' + vendor.toLowerCase() + '-' : '';
|
|
var transform = prefixStyle('transform');
|
|
var transition = prefixStyle('transition');
|
|
var hasPerspective = inBrowser && prefixStyle('perspective') in elementStyle;
|
|
var style = {
|
|
transform: transform,
|
|
transition: transition,
|
|
transitionTimingFunction: prefixStyle('transitionTimingFunction'),
|
|
transitionDuration: prefixStyle('transitionDuration'),
|
|
transitionDelay: prefixStyle('transitionDelay'),
|
|
transformOrigin: prefixStyle('transformOrigin'),
|
|
transitionEnd: prefixStyle('transitionEnd'),
|
|
transitionProperty: prefixStyle('transitionProperty'),
|
|
};
|
|
function preventDefaultExceptionFn(el, exceptions) {
|
|
for (var i in exceptions) {
|
|
if (exceptions[i].test(el[i])) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
var EventRegister = /** @class */ (function () {
|
|
function EventRegister(wrapper, events) {
|
|
this.wrapper = wrapper;
|
|
this.events = events;
|
|
this.addDOMEvents();
|
|
}
|
|
EventRegister.prototype.destroy = function () {
|
|
this.removeDOMEvents();
|
|
this.events = [];
|
|
};
|
|
EventRegister.prototype.addDOMEvents = function () {
|
|
this.handleDOMEvents(addEvent);
|
|
};
|
|
EventRegister.prototype.removeDOMEvents = function () {
|
|
this.handleDOMEvents(removeEvent);
|
|
};
|
|
EventRegister.prototype.handleDOMEvents = function (eventOperation) {
|
|
var _this = this;
|
|
var wrapper = this.wrapper;
|
|
this.events.forEach(function (event) {
|
|
eventOperation(wrapper, event.name, _this, !!event.capture);
|
|
});
|
|
};
|
|
EventRegister.prototype.handleEvent = function (e) {
|
|
var eventType = e.type;
|
|
this.events.some(function (event) {
|
|
if (event.name === eventType) {
|
|
event.handler(e);
|
|
return true;
|
|
}
|
|
return false;
|
|
});
|
|
};
|
|
return EventRegister;
|
|
}());
|
|
|
|
var MouseWheel = /** @class */ (function () {
|
|
function MouseWheel(scroll) {
|
|
this.scroll = scroll;
|
|
this.wheelEndTimer = 0;
|
|
this.wheelMoveTimer = 0;
|
|
this.wheelStart = false;
|
|
this.init();
|
|
}
|
|
MouseWheel.prototype.init = function () {
|
|
this.handleBScroll();
|
|
this.handleOptions();
|
|
this.handleHooks();
|
|
this.registerEvent();
|
|
};
|
|
MouseWheel.prototype.handleBScroll = function () {
|
|
this.scroll.registerType([
|
|
'alterOptions',
|
|
'mousewheelStart',
|
|
'mousewheelMove',
|
|
'mousewheelEnd',
|
|
]);
|
|
};
|
|
MouseWheel.prototype.handleOptions = function () {
|
|
var userOptions = (this.scroll.options.mouseWheel === true
|
|
? {}
|
|
: this.scroll.options.mouseWheel);
|
|
var defaultOptions = {
|
|
speed: 20,
|
|
invert: false,
|
|
easeTime: 300,
|
|
discreteTime: 400,
|
|
throttleTime: 0,
|
|
dampingFactor: 0.1,
|
|
};
|
|
this.mouseWheelOpt = extend(defaultOptions, userOptions);
|
|
};
|
|
MouseWheel.prototype.handleHooks = function () {
|
|
this.hooksFn = [];
|
|
this.registerHooks(this.scroll.hooks, 'destroy', this.destroy);
|
|
};
|
|
MouseWheel.prototype.registerEvent = function () {
|
|
this.eventRegister = new EventRegister(this.scroll.scroller.wrapper, [
|
|
{
|
|
name: 'wheel',
|
|
handler: this.wheelHandler.bind(this),
|
|
},
|
|
{
|
|
name: 'mousewheel',
|
|
handler: this.wheelHandler.bind(this),
|
|
},
|
|
{
|
|
name: 'DOMMouseScroll',
|
|
handler: this.wheelHandler.bind(this),
|
|
},
|
|
]);
|
|
};
|
|
MouseWheel.prototype.registerHooks = function (hooks, name, handler) {
|
|
hooks.on(name, handler, this);
|
|
this.hooksFn.push([hooks, name, handler]);
|
|
};
|
|
MouseWheel.prototype.wheelHandler = function (e) {
|
|
if (!this.scroll.enabled) {
|
|
return;
|
|
}
|
|
this.beforeHandler(e);
|
|
// start
|
|
if (!this.wheelStart) {
|
|
this.wheelStartHandler(e);
|
|
this.wheelStart = true;
|
|
}
|
|
// move
|
|
var delta = this.getWheelDelta(e);
|
|
this.wheelMoveHandler(delta);
|
|
// end
|
|
this.wheelEndDetector(delta);
|
|
};
|
|
MouseWheel.prototype.wheelStartHandler = function (e) {
|
|
this.cleanCache();
|
|
var _a = this.scroll.scroller, scrollBehaviorX = _a.scrollBehaviorX, scrollBehaviorY = _a.scrollBehaviorY;
|
|
scrollBehaviorX.setMovingDirection(0 /* Default */);
|
|
scrollBehaviorY.setMovingDirection(0 /* Default */);
|
|
scrollBehaviorX.setDirection(0 /* Default */);
|
|
scrollBehaviorY.setDirection(0 /* Default */);
|
|
this.scroll.trigger(this.scroll.eventTypes.alterOptions, this.mouseWheelOpt);
|
|
this.scroll.trigger(this.scroll.eventTypes.mousewheelStart);
|
|
};
|
|
MouseWheel.prototype.cleanCache = function () {
|
|
this.deltaCache = [];
|
|
};
|
|
MouseWheel.prototype.wheelMoveHandler = function (delta) {
|
|
var _this = this;
|
|
var _a = this.mouseWheelOpt, throttleTime = _a.throttleTime, dampingFactor = _a.dampingFactor;
|
|
if (throttleTime && this.wheelMoveTimer) {
|
|
this.deltaCache.push(delta);
|
|
}
|
|
else {
|
|
var cachedDelta = this.deltaCache.reduce(function (prev, current) {
|
|
return {
|
|
x: prev.x + current.x,
|
|
y: prev.y + current.y,
|
|
};
|
|
}, { x: 0, y: 0 });
|
|
this.cleanCache();
|
|
var _b = this.scroll.scroller, scrollBehaviorX = _b.scrollBehaviorX, scrollBehaviorY = _b.scrollBehaviorY;
|
|
scrollBehaviorX.setMovingDirection(-delta.directionX);
|
|
scrollBehaviorY.setMovingDirection(-delta.directionY);
|
|
scrollBehaviorX.setDirection(delta.x);
|
|
scrollBehaviorY.setDirection(delta.y);
|
|
// when out of boundary, perform a damping scroll
|
|
var newX = scrollBehaviorX.performDampingAlgorithm(Math.round(delta.x) + cachedDelta.x, dampingFactor);
|
|
var newY = scrollBehaviorY.performDampingAlgorithm(Math.round(delta.y) + cachedDelta.x, dampingFactor);
|
|
if (!this.scroll.trigger(this.scroll.eventTypes.mousewheelMove, {
|
|
x: newX,
|
|
y: newY,
|
|
})) {
|
|
var easeTime = this.getEaseTime();
|
|
if (newX !== this.scroll.x || newY !== this.scroll.y) {
|
|
this.scroll.scrollTo(newX, newY, easeTime);
|
|
}
|
|
}
|
|
if (throttleTime) {
|
|
this.wheelMoveTimer = window.setTimeout(function () {
|
|
_this.wheelMoveTimer = 0;
|
|
}, throttleTime);
|
|
}
|
|
}
|
|
};
|
|
MouseWheel.prototype.wheelEndDetector = function (delta) {
|
|
var _this = this;
|
|
window.clearTimeout(this.wheelEndTimer);
|
|
this.wheelEndTimer = window.setTimeout(function () {
|
|
_this.wheelStart = false;
|
|
window.clearTimeout(_this.wheelMoveTimer);
|
|
_this.wheelMoveTimer = 0;
|
|
_this.scroll.trigger(_this.scroll.eventTypes.mousewheelEnd, delta);
|
|
}, this.mouseWheelOpt.discreteTime);
|
|
};
|
|
MouseWheel.prototype.getWheelDelta = function (e) {
|
|
var _a = this.mouseWheelOpt, speed = _a.speed, invert = _a.invert;
|
|
var wheelDeltaX = 0;
|
|
var wheelDeltaY = 0;
|
|
var direction = invert ? -1 /* Negative */ : 1 /* Positive */;
|
|
switch (true) {
|
|
case 'deltaX' in e:
|
|
if (e.deltaMode === 1) {
|
|
wheelDeltaX = -e.deltaX * speed;
|
|
wheelDeltaY = -e.deltaY * speed;
|
|
}
|
|
else {
|
|
wheelDeltaX = -e.deltaX;
|
|
wheelDeltaY = -e.deltaY;
|
|
}
|
|
break;
|
|
case 'wheelDeltaX' in e:
|
|
wheelDeltaX = (e.wheelDeltaX / 120) * speed;
|
|
wheelDeltaY = (e.wheelDeltaY / 120) * speed;
|
|
break;
|
|
case 'wheelDelta' in e:
|
|
wheelDeltaX = wheelDeltaY = (e.wheelDelta / 120) * speed;
|
|
break;
|
|
case 'detail' in e:
|
|
wheelDeltaX = wheelDeltaY = (-e.detail / 3) * speed;
|
|
break;
|
|
}
|
|
wheelDeltaX *= direction;
|
|
wheelDeltaY *= direction;
|
|
if (!this.scroll.hasVerticalScroll) {
|
|
wheelDeltaX = wheelDeltaY;
|
|
wheelDeltaY = 0;
|
|
}
|
|
if (!this.scroll.hasHorizontalScroll) {
|
|
wheelDeltaX = 0;
|
|
}
|
|
var directionX = wheelDeltaX > 0
|
|
? -1 /* Negative */
|
|
: wheelDeltaX < 0
|
|
? 1 /* Positive */
|
|
: 0 /* Default */;
|
|
var directionY = wheelDeltaY > 0
|
|
? -1 /* Negative */
|
|
: wheelDeltaY < 0
|
|
? 1 /* Positive */
|
|
: 0 /* Default */;
|
|
return {
|
|
x: wheelDeltaX,
|
|
y: wheelDeltaY,
|
|
directionX: directionX,
|
|
directionY: directionY,
|
|
};
|
|
};
|
|
MouseWheel.prototype.beforeHandler = function (e) {
|
|
var _a = this.scroll.options, preventDefault = _a.preventDefault, stopPropagation = _a.stopPropagation, preventDefaultException = _a.preventDefaultException;
|
|
if (preventDefault &&
|
|
!preventDefaultExceptionFn(e.target, preventDefaultException)) {
|
|
e.preventDefault();
|
|
}
|
|
if (stopPropagation) {
|
|
e.stopPropagation();
|
|
}
|
|
};
|
|
MouseWheel.prototype.getEaseTime = function () {
|
|
var SAFE_EASETIME = 100;
|
|
var easeTime = this.mouseWheelOpt.easeTime;
|
|
// scrollEnd event will be triggered in every calling of scrollTo when easeTime is too small
|
|
// easeTime needs to be greater than 100
|
|
if (easeTime < SAFE_EASETIME) {
|
|
warn("easeTime should be greater than 100." +
|
|
"If mouseWheel easeTime is too small," +
|
|
"scrollEnd will be triggered many times.");
|
|
}
|
|
return Math.max(easeTime, SAFE_EASETIME);
|
|
};
|
|
MouseWheel.prototype.destroy = function () {
|
|
this.eventRegister.destroy();
|
|
window.clearTimeout(this.wheelEndTimer);
|
|
window.clearTimeout(this.wheelMoveTimer);
|
|
this.hooksFn.forEach(function (item) {
|
|
var hooks = item[0];
|
|
var hooksName = item[1];
|
|
var handlerFn = item[2];
|
|
hooks.off(hooksName, handlerFn);
|
|
});
|
|
};
|
|
MouseWheel.pluginName = 'mouseWheel';
|
|
MouseWheel.applyOrder = "pre" /* Pre */;
|
|
return MouseWheel;
|
|
}());
|
|
|
|
export default MouseWheel;
|