UNPKG

seamless-scroll-react

Version:
414 lines (342 loc) 12.4 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } var React = require('react'); var React__default = _interopDefault(React); var throttleDebounce = require('throttle-debounce'); function dataWarm(list) { if (list && typeof list !== 'boolean' && list.length >= 400) { console.warn("\u6570\u636E\u8FBE\u5230\u4E86" + list.length + "\u6761\u6709\u70B9\u591A\u54E6~,\u53EF\u80FD\u4F1A\u9020\u6210\u90E8\u5206\u8001\u65E7\u6D4F\u89C8\u5668\u5361\u987F\u3002"); } } /** * 无缝滚动组件 * @param props SeamlessScrollType * @param ref ref * @returns ReactNode */ var ReactSeamlessScroll = function ReactSeamlessScroll(props, ref) { var _props$copyNum; var _props$list = props.list, list = _props$list === void 0 ? [] : _props$list, _props$limitScrollNum = props.limitScrollNum, limitScrollNum = _props$limitScrollNum === void 0 ? 3 : _props$limitScrollNum, _props$hover = props.hover, hover = _props$hover === void 0 ? false : _props$hover, _props$wheel = props.wheel, wheel = _props$wheel === void 0 ? false : _props$wheel, _props$isRemUnit = props.isRemUnit, isRemUnit = _props$isRemUnit === void 0 ? false : _props$isRemUnit, _props$isAutoScroll = props.isAutoScroll, isAutoScroll = _props$isAutoScroll === void 0 ? true : _props$isAutoScroll, _props$ease = props.ease, ease = _props$ease === void 0 ? 'ease-in' : _props$ease, _props$delay = props.delay, delay = _props$delay === void 0 ? 0 : _props$delay, _props$singleWaitTime = props.singleWaitTime, singleWaitTime = _props$singleWaitTime === void 0 ? 1000 : _props$singleWaitTime, _props$direction = props.direction, direction = _props$direction === void 0 ? 'up' : _props$direction, _props$singleWidth = props.singleWidth, singleWidth = _props$singleWidth === void 0 ? 0 : _props$singleWidth, _props$singleHeight = props.singleHeight, singleHeight = _props$singleHeight === void 0 ? 0 : _props$singleHeight, _props$step = props.step, step = _props$step === void 0 ? 1 : _props$step, _props$count = props.count, count = _props$count === void 0 ? -1 : _props$count, children = props.children, wrapperClassName = props.wrapperClassName, wrapperHeight = props.wrapperHeight; var copyNum = new Array((_props$copyNum = props.copyNum) != null ? _props$copyNum : 1).fill(null); var scrollRef = React.useRef(null); var slotListRef = React.useRef(null); var realBoxRef = React.useRef(null); var realBoxWidth = React.useRef(0); var realBoxHeight = React.useRef(0); var reqFrame = React.useRef(null); var singleWaitTimeout = React.useRef(null); var _useState = React.useState(0), xPosState = _useState[0], setXpos = _useState[1]; var _useState2 = React.useState(0), yPosState = _useState2[0], setYpos = _useState2[1]; var xPos = React.useRef(xPosState); var yPos = React.useRef(yPosState); xPos.current = xPosState; yPos.current = yPosState; // 记录滚动次数 var _count = React.useRef(0); // 是否能滚动 var isScroll = React.useMemo(function () { return list ? list.length >= limitScrollNum : false; }, [limitScrollNum, list]); // 真实盒子的样式 var realBoxStyle = React.useMemo(function () { return { width: realBoxWidth.current ? realBoxWidth.current + "px" : 'auto', transform: "translate(" + xPosState + "px," + yPosState + "px)", transition: "all " + (typeof ease === 'string' ? ease : 'cubic-bezier(' + ease.x1 + ',' + ease.y1 + ',' + ease.x2 + ',' + ease.y2 + ')') + " " + delay + "ms", overflow: 'hidden' }; }, [delay, ease, xPosState, yPosState]); // 是否水平滚动 var isHorizontal = React.useMemo(function () { return direction === 'left' || direction === 'right'; }, [direction]); // 是否开启鼠标移入事件 var isHoverStop = React.useMemo(function () { return hover && isAutoScroll && isScroll; }, [hover, isScroll, isAutoScroll]); // children列表div样式 var floatStyle = React.useMemo(function () { return isHorizontal ? { float: 'left', overflow: 'hidden' } : { overflow: 'hidden' }; }, [isHorizontal]); // 基础字体大小 默认为1px var baseFontSize = React.useMemo(function () { return isRemUnit ? parseInt(globalThis.window.getComputedStyle(globalThis.document.documentElement, null).fontSize) : 1; }, [isRemUnit]); // 横向单步大小 var realSingleStopWidth = React.useMemo(function () { return singleWidth * baseFontSize; }, [baseFontSize, singleWidth]); // 纵向单步大小 var realSingleStopHeight = React.useMemo(function () { return singleHeight * baseFontSize; }, [singleHeight, baseFontSize]); // 滚动频率 var stepCount = React.useMemo(function () { var singleStep; var _step = step; if (isHorizontal) { singleStep = realSingleStopWidth; } else { singleStep = realSingleStopHeight; } if (singleStep > 0 && singleStep % _step > 0) { console.warn('如果设置了单步滚动,step 需是单步大小的约数,否则无法保证单步滚动结束的位置是否准确。~~~~~'); } return _step; }, [isHorizontal, step, realSingleStopHeight, realSingleStopWidth]); // 滚动动画 var animation = function animation(_direction, _step, isWheel) { reqFrame.current = requestAnimationFrame(function () { // 无缝滚动 因为复制了一份数组所以要除以2 var h = realBoxHeight.current / 2; var w = realBoxWidth.current / 2; if (_direction === 'up') { if (Math.abs(yPos.current) >= h) { setYpos(0); _count.current += 1; } // 这儿不能else判断 因为单位滚动到临界值时会导致滚动不很连续 setYpos(function (item) { return item -= _step; }); } else if (_direction === 'down') { if (yPos.current >= 0) { setYpos(h * -1); _count.current += 1; } setYpos(function (item) { return item += _step; }); } else if (_direction === 'left') { if (Math.abs(xPos.current) >= w) { setXpos(0); _count.current += 1; } setXpos(function (item) { return item -= _step; }); } else if (_direction === 'right') { if (xPos.current >= 0) { setXpos(w * -1); _count.current += 1; } setXpos(function (item) { return item += _step; }); } // 当滚轮滑动时不能单步滚动 if (isWheel) return; if (singleWaitTimeout.current) { clearTimeout(singleWaitTimeout.current); } // 单步滚动 if (!!realSingleStopHeight) { if (Math.abs(yPos.current) % realSingleStopHeight === 0) { singleWaitTimeout.current = setTimeout(function () { move(); }, singleWaitTime); } else { move(); } } else if (!!realSingleStopWidth) { if (Math.abs(xPos.current) % realSingleStopWidth < _step) { singleWaitTimeout.current = setTimeout(function () { move(); }, singleWaitTime); } else { move(); } } else { move(); } }); }; // 滚动动画核心 var move = function move() { cancle(); if (!isAutoScroll || !isScroll || _count.current === count) { _count.current = 0; return; } animation(direction, stepCount, false); }; // 初始化滚动 var initMove = function initMove() { dataWarm(list); // 是否横线滚动 if (isHorizontal) { var slotListWidth = slotListRef.current.offsetWidth; realBoxWidth.current = slotListWidth * 2 + 1; } else { realBoxHeight.current = realBoxRef.current.offsetHeight; } move(); }; // 滚轮事件 var throttleFunc = throttleDebounce.throttle(30, function (e) { cancle(); var singleStep = !!realSingleStopHeight ? realSingleStopHeight : 20; if (e.deltaY < 0) { animation('down', singleStep, true); } if (e.deltaY > 0) { animation('up', singleStep, true); } }); // 滚轮事件 var _onWheel = function onWheel(e) { throttleFunc(e); }; // 开始滚动 var startMove = function startMove() { move(); }; // 停止滚动 var stopMove = function stopMove() { if (singleWaitTimeout.current) { clearTimeout(singleWaitTimeout.current); } cancle(); }; // 取消滚动id 避免闭包问题 var cancle = function cancle() { cancelAnimationFrame(reqFrame.current); reqFrame.current = null; }; var reset = function reset() { if (singleWaitTimeout.current) { clearTimeout(singleWaitTimeout.current); } cancle(); initMove(); }; React.useEffect(function () { if (isAutoScroll) { startMove(); } else { stopMove(); } }, [isAutoScroll]); React.useEffect(function () { if (count !== 0) { startMove(); } }, [count]); // 初始化 React.useEffect(function () { cancle(); if (singleWaitTimeout.current) { clearTimeout(singleWaitTimeout.current); } // 如果数据list长度能滚动并且配置了自动滚动 if (isScroll && isAutoScroll) { initMove(); } return function () { stopMove(); }; }, [list]); // 提供的方法 React.useImperativeHandle(ref, function () { return { onReset: function onReset() { reset(); }, onStopMove: function onStopMove() { stopMove(); }, onStartMove: function onStartMove() { startMove(); } }; }); // children列表div var getHtmlMemo = React.useMemo(function () { return React__default.createElement(React__default.Fragment, null, React__default.createElement("div", { ref: slotListRef, style: floatStyle }, children), isScroll ? copyNum.map(function (_, i) { return React__default.createElement("div", { key: i, style: floatStyle }, children); }) : null); }, [list]); return React__default.createElement("div", { ref: scrollRef, className: wrapperClassName, style: { height: wrapperHeight || realBoxHeight.current / 2, overflow: 'hidden' } }, wheel && hover ? React__default.createElement("div", { ref: realBoxRef, style: realBoxStyle, onMouseEnter: function onMouseEnter() { if (isHoverStop) { stopMove(); } }, onMouseLeave: function onMouseLeave() { if (isHoverStop) { startMove(); } }, onWheel: function onWheel(e) { if (isHoverStop) { _onWheel(e); } } }, getHtmlMemo) : React__default.createElement("div", { ref: realBoxRef, style: realBoxStyle, onMouseEnter: function onMouseEnter() { if (isHoverStop) { stopMove(); } }, onMouseLeave: function onMouseLeave() { if (isHoverStop) { startMove(); } } }, getHtmlMemo)); }; var SeamlessScroll = /*#__PURE__*/React.memo( /*#__PURE__*/React.forwardRef(ReactSeamlessScroll)); /** * 处理requestAnimationFrame兼容问题 */ globalThis.window.cancelAnimationFrame = /*#__PURE__*/function () { return globalThis.window.cancelAnimationFrame || // @ts-ignore globalThis.window.webkitCancelAnimationFrame || // @ts-ignore globalThis.window.mozCancelAnimationFrame || // @ts-ignore globalThis.window.oCancelAnimationFrame || // @ts-ignore globalThis.window.msCancelAnimationFrame || function (id) { return globalThis.window.clearTimeout(id); }; }(); globalThis.window.requestAnimationFrame = /*#__PURE__*/function () { return globalThis.window.requestAnimationFrame || // @ts-ignore globalThis.window.webkitRequestAnimationFrame || // @ts-ignore globalThis.window.mozRequestAnimationFrame || // @ts-ignore globalThis.window.oRequestAnimationFrame || // @ts-ignore globalThis.window.msRequestAnimationFrame || function (callback) { return globalThis.window.setTimeout(callback, 1000 / 60); }; }(); exports.default = SeamlessScroll; //# sourceMappingURL=seamless-scroll-react.cjs.development.js.map