Skip to content

Commit

Permalink
feat(Carousel):滚动效果保持总是从左向右滚动 (#695)
Browse files Browse the repository at this point in the history
  • Loading branch information
nullptr-z committed Mar 21, 2022
1 parent a6a2f47 commit d10f59a
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 12 deletions.
10 changes: 9 additions & 1 deletion packages/react-carousel/README.md
Expand Up @@ -91,7 +91,13 @@ function Demo() {

return (
<React.Fragment>
<Carousel ref={ref} position={2} autoPlay={autoPlay}>
<Carousel
ref={ref}
position={2}
autoPlay={autoPlay}
afterChange={(current)=>console.log('after',current)}
beforeChange={(current)=>console.log('before',current)}
>
<div style={{ height: '100%', background: '#1EABCD' }}>
<span>1</span>
</div>
Expand Down Expand Up @@ -128,6 +134,8 @@ ReactDOM.render(<Demo />, _mount_);
| palyTime | 每帧停留时间(ms) | number | 2000 |
| scrollTime | 滚动动画的速度(ms) | number | 200 |
| autoPlay | 是否自动播放 | boolean | true |
| afterChange | 切换面板前的回调 | (current) => void | - |
| beforeChange | 切换面板后的回调 | (current) => void | - |


### ref
Expand Down
49 changes: 38 additions & 11 deletions packages/react-carousel/src/index.tsx
Expand Up @@ -9,6 +9,8 @@ export interface CarouselProps extends IProps, HTMLDivProps {
palyTime?: number;
scrollTime?: number;
autoPlay?: boolean;
afterChange?: (current: number) => void;
beforeChange?: (current: number) => void;
}

export interface CarouselRef {
Expand All @@ -18,14 +20,16 @@ export interface CarouselRef {
stopPlay: () => void;
}

function Carousel(props: CarouselProps, ref: CarouselRef) {
function Carousel(props: CarouselProps, ref: React.ForwardedRef<CarouselRef>) {
const {
position = 0,
width = 400,
height = 200,
palyTime = 2000,
scrollTime = 200,
autoPlay = true,
afterChange,
beforeChange,

prefixCls = 'w-carousel',
className,
Expand All @@ -35,23 +39,24 @@ function Carousel(props: CarouselProps, ref: CarouselRef) {
const cls = useMemo(() => [prefixCls, className].filter(Boolean).join(' ').trim(), [prefixCls, className]);

const [currentPosition, currentPositionSet] = useState(position);
const [transitionInner, transitionInnerSet] = useState(`${scrollTime * 0.001}s ease-in-out`);
const positionRef = useRef(currentPosition);
const childCount = React.Children.count(props.children);
const stopPlay = useRef<Function>(() => {});
const childCount = React.Children.count(props.children) + 1;
const stopPlay = useRef({ stop: () => {}, after: afterChange, before: beforeChange });

React.useImperativeHandle(
ref,
() => ({
gotoSlide,
prevSlide: () => gotoSlide(positionRef.current - 1),
nextSlide: () => gotoSlide(positionRef.current + 1),
stopPlay: () => stopPlay.current(),
stopPlay: () => stopPlay.current.stop(),
}),
[ref],
);

const gotoSlide = (slidNumber: number) => {
stopPlay.current();
stopPlay.current.stop();
const maxSlid = childCount - 1;
let slidNumberTemp = slidNumber > maxSlid ? maxSlid : slidNumber;
slidNumberTemp = slidNumber < 0 ? 0 : slidNumberTemp;
Expand All @@ -63,13 +68,15 @@ function Carousel(props: CarouselProps, ref: CarouselRef) {
const play = (ms: number = palyTime) => {
if (autoPlay) {
const time = setInterval(() => {
stopPlay.current.after?.(positionRef.current);
positionRef.current++;
if (positionRef.current >= childCount) {
positionRef.current = 0;
}
currentPositionSet(positionRef.current);
stopPlay.current.before?.(positionRef.current);
}, ms);
stopPlay.current = () => {
stopPlay.current.stop = () => {
clearInterval(time);
};
}
Expand All @@ -78,23 +85,43 @@ function Carousel(props: CarouselProps, ref: CarouselRef) {
useEffect(() => {
play();
return () => {
stopPlay.current();
stopPlay.current.stop();
};
}, [autoPlay]);

useEffect(() => {
let time: NodeJS.Timeout;
if (childCount === currentPosition + 1) {
time = setTimeout(() => {
stopPlay.current.before = () => {
transitionInnerSet(`${scrollTime * 0.001}s ease-in-out`);
stopPlay.current.before = props.beforeChange;
};
transitionInnerSet('none');
gotoSlide(0);
}, scrollTime);
}
return () => {
clearTimeout(time);
};
}, [currentPosition]);

const childrens = React.Children.map(props.children, (child) => {
return <div style={{ width, height, ...style }}>{child}</div>;
});

return (
<div className={cls} style={{ width, height }}>
<div
className={`${cls}-content`}
style={{
width: width * childCount,
transform: `translate3d(${-(currentPosition * width)}px, 0px, 0px)`,
transition: `${scrollTime * 0.001}s ease-in-out`,
transition: transitionInner,
}}
>
{React.Children.map(props.children, (child) => {
return <div style={{ width, height, ...style }}>{child}</div>;
})}
{childrens}
<div style={{ width, height, ...style }}>{childrens?.[0]}</div>
</div>
</div>
);
Expand Down

0 comments on commit d10f59a

Please sign in to comment.