Skip to content

Commit d10f59a

Browse files
authoredMar 21, 2022
feat(Carousel):滚动效果保持总是从左向右滚动 (#695)
1 parent a6a2f47 commit d10f59a

File tree

2 files changed

+47
-12
lines changed

2 files changed

+47
-12
lines changed
 

‎packages/react-carousel/README.md

+9-1
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,13 @@ function Demo() {
9191

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

132140

133141
### ref

‎packages/react-carousel/src/index.tsx

+38-11
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ export interface CarouselProps extends IProps, HTMLDivProps {
99
palyTime?: number;
1010
scrollTime?: number;
1111
autoPlay?: boolean;
12+
afterChange?: (current: number) => void;
13+
beforeChange?: (current: number) => void;
1214
}
1315

1416
export interface CarouselRef {
@@ -18,14 +20,16 @@ export interface CarouselRef {
1820
stopPlay: () => void;
1921
}
2022

21-
function Carousel(props: CarouselProps, ref: CarouselRef) {
23+
function Carousel(props: CarouselProps, ref: React.ForwardedRef<CarouselRef>) {
2224
const {
2325
position = 0,
2426
width = 400,
2527
height = 200,
2628
palyTime = 2000,
2729
scrollTime = 200,
2830
autoPlay = true,
31+
afterChange,
32+
beforeChange,
2933

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

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

4247
React.useImperativeHandle(
4348
ref,
4449
() => ({
4550
gotoSlide,
4651
prevSlide: () => gotoSlide(positionRef.current - 1),
4752
nextSlide: () => gotoSlide(positionRef.current + 1),
48-
stopPlay: () => stopPlay.current(),
53+
stopPlay: () => stopPlay.current.stop(),
4954
}),
5055
[ref],
5156
);
5257

5358
const gotoSlide = (slidNumber: number) => {
54-
stopPlay.current();
59+
stopPlay.current.stop();
5560
const maxSlid = childCount - 1;
5661
let slidNumberTemp = slidNumber > maxSlid ? maxSlid : slidNumber;
5762
slidNumberTemp = slidNumber < 0 ? 0 : slidNumberTemp;
@@ -63,13 +68,15 @@ function Carousel(props: CarouselProps, ref: CarouselRef) {
6368
const play = (ms: number = palyTime) => {
6469
if (autoPlay) {
6570
const time = setInterval(() => {
71+
stopPlay.current.after?.(positionRef.current);
6672
positionRef.current++;
6773
if (positionRef.current >= childCount) {
6874
positionRef.current = 0;
6975
}
7076
currentPositionSet(positionRef.current);
77+
stopPlay.current.before?.(positionRef.current);
7178
}, ms);
72-
stopPlay.current = () => {
79+
stopPlay.current.stop = () => {
7380
clearInterval(time);
7481
};
7582
}
@@ -78,23 +85,43 @@ function Carousel(props: CarouselProps, ref: CarouselRef) {
7885
useEffect(() => {
7986
play();
8087
return () => {
81-
stopPlay.current();
88+
stopPlay.current.stop();
8289
};
8390
}, [autoPlay]);
8491

92+
useEffect(() => {
93+
let time: NodeJS.Timeout;
94+
if (childCount === currentPosition + 1) {
95+
time = setTimeout(() => {
96+
stopPlay.current.before = () => {
97+
transitionInnerSet(`${scrollTime * 0.001}s ease-in-out`);
98+
stopPlay.current.before = props.beforeChange;
99+
};
100+
transitionInnerSet('none');
101+
gotoSlide(0);
102+
}, scrollTime);
103+
}
104+
return () => {
105+
clearTimeout(time);
106+
};
107+
}, [currentPosition]);
108+
109+
const childrens = React.Children.map(props.children, (child) => {
110+
return <div style={{ width, height, ...style }}>{child}</div>;
111+
});
112+
85113
return (
86114
<div className={cls} style={{ width, height }}>
87115
<div
88116
className={`${cls}-content`}
89117
style={{
90118
width: width * childCount,
91119
transform: `translate3d(${-(currentPosition * width)}px, 0px, 0px)`,
92-
transition: `${scrollTime * 0.001}s ease-in-out`,
120+
transition: transitionInner,
93121
}}
94122
>
95-
{React.Children.map(props.children, (child) => {
96-
return <div style={{ width, height, ...style }}>{child}</div>;
97-
})}
123+
{childrens}
124+
<div style={{ width, height, ...style }}>{childrens?.[0]}</div>
98125
</div>
99126
</div>
100127
);

0 commit comments

Comments
 (0)
Please sign in to comment.