acud
Version:
acg react 组件库
210 lines • 8.26 kB
JavaScript
import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray";
import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
import React, { useState, useEffect, useRef, useMemo, useCallback } from 'react';
import classNames from 'classnames';
import { ConfigContext } from '../config-provider';
import CarouselSwitch from './switch';
import CarouselIndicator from './indicator';
var Carousel = function Carousel(_ref) {
var className = _ref.className,
style = _ref.style,
children = _ref.children,
_ref$dotPosition = _ref.dotPosition,
dotPosition = _ref$dotPosition === void 0 ? 'bottom' : _ref$dotPosition,
_ref$playInterval = _ref.playInterval,
playInterval = _ref$playInterval === void 0 ? 5000 : _ref$playInterval,
_ref$autoplay = _ref.autoplay,
autoplay = _ref$autoplay === void 0 ? true : _ref$autoplay,
_ref$width = _ref.width,
width = _ref$width === void 0 ? 1920 : _ref$width,
_ref$dotType = _ref.dotType,
dotType = _ref$dotType === void 0 ? 'dot' : _ref$dotType,
_ref$animationTime = _ref.animationTime,
animationTime = _ref$animationTime === void 0 ? 400 : _ref$animationTime,
multi = _ref.multi,
_ref$showNumber = _ref.showNumber,
showNumber = _ref$showNumber === void 0 ? 3 : _ref$showNumber,
_ref$multiShift = _ref.multiShift,
multiShift = _ref$multiShift === void 0 ? false : _ref$multiShift,
indicatorStyle = _ref.indicatorStyle,
_ref$infinite = _ref.infinite,
infinite = _ref$infinite === void 0 ? true : _ref$infinite;
var carouselRef = useRef();
var timer = useRef();
var _useState = useState(false),
_useState2 = _slicedToArray(_useState, 2),
isHover = _useState2[0],
setIsHover = _useState2[1];
var _React$useContext = React.useContext(ConfigContext),
getPrefixCls = _React$useContext.getPrefixCls;
var prefixCls = getPrefixCls('carousel');
// 判断子元素是否是数组,如果不是,那就不存在轮播的情况
var childrenIsArray = useMemo(function () {
return Array.isArray(children);
}, [children]);
// 因为要实现无缝轮播,所以前后会增加一个key。例如对用户看到有3张图片,但渲染中前后会添加得到5张
var extraCount = multi ? showNumber : 1;
var _useState3 = useState({
lastKey: extraCount,
currentKey: extraCount
}),
_useState4 = _slicedToArray(_useState3, 2),
_useState4$ = _useState4[0],
lastKey = _useState4$.lastKey,
currentKey = _useState4$.currentKey,
setKey = _useState4[1];
var length = Array.isArray(children) ? children.length : undefined;
var next = useCallback(function () {
// 向右滑动,最后一帧无缝滑动到第一帧使用的是额外添加的帧,滑动动画结束后,立刻切换到原始帧
if (infinite) {
if (currentKey === length + extraCount) {
setKey({
lastKey: currentKey,
currentKey: extraCount
});
setTimeout(function () {
// 重置掉自动轮播
clearTimeout(timer.current);
var nextKey = extraCount + (multiShift ? extraCount : 1);
setKey({
lastKey: extraCount,
currentKey: nextKey > length + extraCount ? length + extraCount : nextKey
});
}, 100);
} else {
var nextKey = currentKey + (multiShift ? extraCount : 1);
setKey({
lastKey: currentKey,
currentKey: nextKey > length + extraCount ? length + extraCount : nextKey
});
}
} else {
var _nextKey = currentKey + (multiShift ? extraCount : 1);
setKey({
lastKey: currentKey,
currentKey: _nextKey > length + extraCount ? length + extraCount : _nextKey
});
}
}, [currentKey, extraCount, length, multiShift, infinite]);
// 向左滑动,第一帧无缝滑动到最后一帧使用的是额外添加的帧,滑动动画结束后,立刻切换到原始帧
var prev = useCallback(function () {
if (infinite) {
if (currentKey === 0) {
setKey({
lastKey: currentKey,
currentKey: length
});
setTimeout(function () {
// 重置掉自动轮播
clearTimeout(timer.current);
var nextKey = length - (multiShift ? extraCount : 1);
setKey({
lastKey: length,
currentKey: nextKey < 0 ? 0 : length - (multiShift ? extraCount : 1)
});
});
} else {
var nextKey = currentKey - (multiShift ? extraCount : 1);
setKey({
lastKey: currentKey,
currentKey: nextKey < 0 ? 0 : currentKey - (multiShift ? extraCount : 1)
});
}
} else {
var _nextKey2 = currentKey - (multiShift ? extraCount : 1);
setKey({
lastKey: currentKey,
currentKey: _nextKey2 < 0 ? 0 : _nextKey2
});
}
}, [currentKey, extraCount, length, multiShift, infinite]);
// 监听是否hover热区,hover情况下不会自动轮播
useEffect(function () {
carouselRef.current.addEventListener('mouseover', function () {
setIsHover(true);
});
carouselRef.current.addEventListener('mouseleave', function () {
setIsHover(false);
});
});
// 自动轮播
useEffect(function () {
clearTimeout(timer.current);
if (length > 1 && autoplay && !isHover) {
timer.current = setTimeout(next, playInterval);
}
return function () {
return clearTimeout(timer.current);
};
}, [autoplay, length, playInterval, next, isHover]);
var getDuration = useCallback(function () {
// next中立即切换的情况
if (lastKey === length + extraCount && currentKey === extraCount) {
return '0s';
}
// prev中立即切换的情况
if (lastKey === 0 && currentKey === length) {
return '0s';
}
// 正常切换的情况
return "".concat(animationTime / 1000, "s");
}, [lastKey, length, extraCount, currentKey, animationTime]);
// 渲染的元素数组,首位增加实现无缝轮播
var renderChildren = useMemo(function () {
var elements = Array.isArray(children) ? children : [children];
if (elements.length >= 1) {
var extraPre = elements.slice(elements.length - extraCount);
var extraPost = elements.slice(0, extraCount);
elements = [].concat(_toConsumableArray(extraPre), _toConsumableArray(elements), _toConsumableArray(extraPost));
}
return elements;
}, [children, extraCount]);
var cardWidth = useMemo(function () {
if (multi) {
return (width - 4 * (extraCount - 1)) / extraCount;
}
return width;
}, [multi, width, extraCount]);
var getLeft = function getLeft(idx) {
return (multi ? cardWidth + 8 : cardWidth) * (idx - currentKey);
};
var wrapperClassName = classNames(prefixCls, className, _defineProperty({}, "".concat(prefixCls, "-multi"), multi));
var isPrevDisabled = !infinite && currentKey === extraCount;
var isNextDisabled = !infinite && currentKey === length;
return /*#__PURE__*/React.createElement("div", {
ref: carouselRef,
style: style,
className: wrapperClassName
}, childrenIsArray ? /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(CarouselSwitch, {
prefixCls: prefixCls,
next: next,
prev: prev,
isPrevDisabled: isPrevDisabled,
isNextDisabled: isNextDisabled
}), !multi && /*#__PURE__*/React.createElement(CarouselIndicator, {
prefixCls: prefixCls,
setKey: setKey,
length: length,
currentKey: currentKey,
autoplay: autoplay,
playInterval: playInterval,
dotPosition: dotPosition,
dotType: dotType,
multi: multi,
showNumber: showNumber,
style: indicatorStyle
}), /*#__PURE__*/React.createElement("div", {
className: "".concat(prefixCls, "-content")
}, /*#__PURE__*/React.createElement("ul", null, renderChildren.map(function (child, idx) {
return /*#__PURE__*/React.createElement("li", {
key: idx,
style: {
left: getLeft(idx),
width: cardWidth,
transitionDuration: getDuration()
}
}, child);
})))) : children);
};
export default Carousel;