UNPKG

@orca-fe/hooks

Version:

React Hooks Collections

216 lines (204 loc) 9.68 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default; Object.defineProperty(exports, "__esModule", { value: true }); exports.MANUAL_SCROLL_UP = exports.MANUAL_SCROLL_RIGHT = exports.MANUAL_SCROLL_LEFT = exports.MANUAL_SCROLL_DOWN = void 0; exports.default = useManualScroll; var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2")); var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray")); var _ahooks = require("ahooks"); var _react = require("react"); var _lodashEs = require("lodash-es"); var _domTarget = require("./utils/domTarget"); var _useAnimationFrame = _interopRequireDefault(require("./useAnimationFrame")); var _useEffectWithTarget = _interopRequireDefault(require("./useEffectWithTarget")); var MANUAL_SCROLL_UP = exports.MANUAL_SCROLL_UP = 'up'; // 向上滚动 var MANUAL_SCROLL_DOWN = exports.MANUAL_SCROLL_DOWN = 'down'; // 向下滚动 var MANUAL_SCROLL_LEFT = exports.MANUAL_SCROLL_LEFT = 'left'; // 向左滚动 var MANUAL_SCROLL_RIGHT = exports.MANUAL_SCROLL_RIGHT = 'right'; // 向右滚动 // 基准帧间隔 var baseFrameInterval = 16.67; // 是否水平滚动 var isHorizScroll = function isHorizScroll(direction) { return direction === MANUAL_SCROLL_LEFT || direction === MANUAL_SCROLL_RIGHT; }; function useManualScroll(target) { var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; var _options$defaultScrol = options.defaultScrollStep, defaultScrollStep = _options$defaultScrol === void 0 ? 200 : _options$defaultScrol, _options$duration = options.duration, duration = _options$duration === void 0 ? 300 : _options$duration, _options$shouldUpdate = options.shouldUpdate, shouldUpdate = _options$shouldUpdate === void 0 ? function () { return true; } : _options$shouldUpdate; var _this = (0, _react.useRef)({ scrollDistance: 0, lastFrameTime: null, animDuration: 0, direction: null, scrollStep: defaultScrollStep, scrollOffset: { x: 0, y: 0 } }).current; var _useBoolean = (0, _ahooks.useBoolean)(false), _useBoolean2 = (0, _slicedToArray2.default)(_useBoolean, 2), scrolling = _useBoolean2[0], _useBoolean2$ = _useBoolean2[1], startScrolling = _useBoolean2$.setTrue, stopScrolling = _useBoolean2$.setFalse; var dom = (0, _domTarget.getTargetElement)(target); var size = (0, _ahooks.useSize)(target); // 透传出的容器滚动位置信息(依赖 shouldUpdate) var _useRafState = (0, _ahooks.useRafState)(), _useRafState2 = (0, _slicedToArray2.default)(_useRafState, 2), position = _useRafState2[0], setPosition = _useRafState2[1]; // 保存容器最新的滚动位置信息 var latestPositionRef = (0, _react.useRef)(); var shouldUpdateRef = (0, _ahooks.useLatest)(shouldUpdate); // 根据当前位置获取各方位滚动状态 var scrollBoundaryState = (0, _ahooks.useMemoizedFn)(function (currentPosition) { var _currentPosition$left, _size$width, _dom$scrollWidth, _currentPosition$top, _size$height, _dom$scrollHeight; var scrollToLeft = (currentPosition === null || currentPosition === void 0 ? void 0 : currentPosition.left) === 0; var scrollToRight = Math.ceil(((_currentPosition$left = currentPosition === null || currentPosition === void 0 ? void 0 : currentPosition.left) !== null && _currentPosition$left !== void 0 ? _currentPosition$left : 0) + ((_size$width = size === null || size === void 0 ? void 0 : size.width) !== null && _size$width !== void 0 ? _size$width : 0)) >= ((_dom$scrollWidth = dom === null || dom === void 0 ? void 0 : dom.scrollWidth) !== null && _dom$scrollWidth !== void 0 ? _dom$scrollWidth : 0); var scrollToTop = (currentPosition === null || currentPosition === void 0 ? void 0 : currentPosition.top) === 0; var scrollToBottom = Math.ceil(((_currentPosition$top = currentPosition === null || currentPosition === void 0 ? void 0 : currentPosition.top) !== null && _currentPosition$top !== void 0 ? _currentPosition$top : 0) + ((_size$height = size === null || size === void 0 ? void 0 : size.height) !== null && _size$height !== void 0 ? _size$height : 0)) >= ((_dom$scrollHeight = dom === null || dom === void 0 ? void 0 : dom.scrollHeight) !== null && _dom$scrollHeight !== void 0 ? _dom$scrollHeight : 0); return { scrollToLeft: scrollToLeft, scrollToRight: scrollToRight, scrollToTop: scrollToTop, scrollToBottom: scrollToBottom }; }); // 获取当前帧间隔 var currentFrameInterval = (0, _ahooks.useMemoizedFn)(function (ms, frameTime) { if (!_this.lastFrameTime) { _this.lastFrameTime = frameTime; } var frameInterval = ms - _this.lastFrameTime || baseFrameInterval; return _this.animDuration + frameInterval > duration ? duration - _this.animDuration : frameInterval; }); // 获取当前帧滚动量 var currentFrameStep = (0, _ahooks.useMemoizedFn)(function (frameInterval) { // 基准帧滚动量 var baseFrameStep = _this.scrollStep / (duration / baseFrameInterval); // 帧间隔偏差比例 var deviationRatio = frameInterval / baseFrameInterval; // 当前帧滚动量 var frameStep = deviationRatio * baseFrameStep; return _this.scrollDistance + frameStep > _this.scrollStep ? _this.scrollStep - _this.scrollDistance : frameStep; }); // 是否抵达边界 var isReachToBoundary = (0, _ahooks.useMemoizedFn)(function () { var latestPosition = scrollBoundaryState(latestPositionRef.current); if (_this.direction === MANUAL_SCROLL_LEFT) return latestPosition.scrollToLeft; if (_this.direction === MANUAL_SCROLL_RIGHT) return latestPosition.scrollToRight; if (_this.direction === MANUAL_SCROLL_UP) return latestPosition.scrollToTop; if (_this.direction === MANUAL_SCROLL_DOWN) return latestPosition.scrollToBottom; return false; }); // modify from `useScroll` (0, _useEffectWithTarget.default)(function () { var el = (0, _domTarget.getTargetElement)(target); if (!el) { return; } var updatePosition = function updatePosition() { var _shouldUpdateRef$curr; var newPosition = { left: el.scrollLeft, top: el.scrollTop }; if ((_shouldUpdateRef$curr = shouldUpdateRef.current) !== null && _shouldUpdateRef$curr !== void 0 && _shouldUpdateRef$curr.call(shouldUpdateRef, newPosition)) { setPosition(newPosition); } latestPositionRef.current = newPosition; }; updatePosition(); el.addEventListener('scroll', updatePosition); // eslint-disable-next-line consistent-return return function () { el.removeEventListener('scroll', updatePosition); }; }, [], target); var rafHandler = (0, _useAnimationFrame.default)(function (ms, frameTime) { if (!dom || !_this.direction || _this.animDuration >= duration) { stopScrolling(); return; } if (isReachToBoundary()) { if (isHorizScroll(_this.direction)) _this.scrollOffset.x = 0;else _this.scrollOffset.y = 0; stopScrolling(); return; } // 当前帧间隔 var frameInterval = currentFrameInterval(ms, frameTime); // 当前帧滚动量 var frameStep = currentFrameStep(frameInterval); // 累计滚动量 _this.scrollDistance += frameStep; // 累计动画时间 _this.animDuration += frameInterval; var xScrollValue = 0; var yScrollValue = 0; // 向左滚动 if (_this.direction === MANUAL_SCROLL_LEFT) { xScrollValue = (0, _lodashEs.round)(dom.scrollLeft - frameStep, 2) + _this.scrollOffset.x; } // 向右滚动 if (_this.direction === MANUAL_SCROLL_RIGHT) { xScrollValue = (0, _lodashEs.round)(dom.scrollLeft + frameStep, 2) + _this.scrollOffset.x; } // 向上滚动 if (_this.direction === MANUAL_SCROLL_UP) { yScrollValue = (0, _lodashEs.round)(dom.scrollTop - frameStep, 2) + _this.scrollOffset.y; } // 向下滚动 if (_this.direction === MANUAL_SCROLL_DOWN) { yScrollValue = (0, _lodashEs.round)(dom.scrollTop + frameStep, 2) + _this.scrollOffset.y; } // 滚动并更新误差值 if (isHorizScroll(_this.direction)) { dom.scrollLeft = xScrollValue; _this.scrollOffset.x = xScrollValue - dom.scrollLeft; } else { dom.scrollTop = yScrollValue; _this.scrollOffset.y = yScrollValue - dom.scrollTop; } }, { manual: true }); var run = function run(direction) { var scrollStep = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : defaultScrollStep; _this.direction = direction; _this.scrollStep = scrollStep; var latestPosition = scrollBoundaryState(latestPositionRef.current); if (direction === MANUAL_SCROLL_LEFT && latestPosition.scrollToLeft) return; if (direction === MANUAL_SCROLL_RIGHT && latestPosition.scrollToRight) return; if (direction === MANUAL_SCROLL_UP && latestPosition.scrollToTop) return; if (direction === MANUAL_SCROLL_DOWN && latestPosition.scrollToBottom) return; startScrolling(); }; var _useThrottleFn = (0, _ahooks.useThrottleFn)(run, { wait: duration }), throttleRun = _useThrottleFn.run; (0, _react.useEffect)(function () { if (scrolling) { _this.animDuration = 0; _this.scrollDistance = 0; _this.lastFrameTime = null; rafHandler.start(); } else { rafHandler.stop(); } }, [scrolling]); return (0, _objectSpread2.default)({ position: position, run: (0, _ahooks.useMemoizedFn)(throttleRun) }, scrollBoundaryState(position)); }