Skip to content

Commit 4723874

Browse files
authoredMar 19, 2022
faeat(Carousel): 增加走马灯组件Carousel (#691)
1 parent 1a6768e commit 4723874

File tree

14 files changed

+344
-2
lines changed

14 files changed

+344
-2
lines changed
 

‎.github/workflows/deploy.yml

+5
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,11 @@ jobs:
123123
with:
124124
token: ${{ secrets.NPM_TOKEN }}
125125
package: ./packages/react-card/package.json
126+
- name: 📦 @uiw/react-carousel publish to NPM
127+
uses: JS-DevTools/npm-publish@v1
128+
with:
129+
token: ${{ secrets.NPM_TOKEN }}
130+
package: ./packages/react-carousel/package.json
126131
- name: 📦 @uiw/react-checkbox publish to NPM
127132
uses: JS-DevTools/npm-publish@v1
128133
with:

‎.github/workflows/npm.yml

+5
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,11 @@ jobs:
192192
with:
193193
token: ${{ secrets.NPM_TOKEN }}
194194
package: ./packages/react-card/package.json
195+
- name: 📦 @uiw/react-carousel publish to NPM
196+
uses: JS-DevTools/npm-publish@v1
197+
with:
198+
token: ${{ secrets.NPM_TOKEN }}
199+
package: ./packages/react-carousel/package.json
195200
- name: 📦 @uiw/react-checkbox publish to NPM
196201
uses: JS-DevTools/npm-publish@v1
197202
with:

‎packages/react-carousel/README.md

+140
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
Carousel 走马灯
2+
===
3+
4+
[![Open in unpkg](https://img.shields.io/badge/Open%20in-unpkg-blue)](https://uiwjs.github.io/npm-unpkg/#/pkg/@uiw/react-carousel/file/README.md)
5+
[![NPM Downloads](https://img.shields.io/npm/dm/@uiw/react-carousel.svg?style=flat)](https://www.npmjs.com/package/@uiw/react-carousel)
6+
[![npm version](https://img.shields.io/npm/v/@uiw/react-carousel.svg?label=@uiw/react-carousel)](https://npmjs.com/@uiw/react-carousel)
7+
8+
滚动播放。在 v4.15.0+ 添加。
9+
10+
## 基础用法
11+
12+
最简单的用法。
13+
14+
<!--rehype:bgWhite=true&codeSandbox=true&codePen=true-->
15+
```jsx
16+
import React from 'react';
17+
import { Carousel } from 'uiw';
18+
19+
function Demo() {
20+
return (
21+
<Carousel>
22+
<div style={{ height: '100%', background: '#1EABCD' }}>
23+
<span>1</span>
24+
</div>
25+
<div style={{ height: '100%', background: '#393b46' }}>
26+
<span>2</span>
27+
</div>
28+
<div style={{ height: '100%', background: '#008EF0' }}>
29+
<span>3</span>
30+
</div>
31+
<div style={{ height: '100%', background: '#393E48' }}>
32+
<span>4</span>
33+
</div>
34+
</Carousel>
35+
);
36+
}
37+
38+
ReactDOM.render(<Demo />, _mount_);
39+
```
40+
41+
## 控制播放频率
42+
43+
palyTime设置每帧停留时间,scrollTime设置切换帧的速度
44+
45+
<!--rehype:bgWhite=true&codeSandbox=true&codePen=true-->
46+
```jsx
47+
import React from 'react';
48+
import { Carousel } from 'uiw';
49+
50+
function Demo() {
51+
return (
52+
<Carousel palyTime={1000} scrollTime={500}>
53+
<div style={{ height: '100%', background: '#1EABCD' }}>
54+
<span>1</span>
55+
</div>
56+
<div style={{ height: '100%', background: '#393b46' }}>
57+
<span>2</span>
58+
</div>
59+
<div style={{ height: '100%', background: '#008EF0' }}>
60+
<span>3</span>
61+
</div>
62+
<div style={{ height: '100%', background: '#393E48' }}>
63+
<span>4</span>
64+
</div>
65+
</Carousel>
66+
);
67+
}
68+
69+
ReactDOM.render(<Demo />, _mount_);
70+
```
71+
72+
## 切换到指定帧
73+
74+
手动切换到指定帧的位置
75+
76+
<!--rehype:bgWhite=true&codeSandbox=true&codePen=true-->
77+
```jsx
78+
import React from 'react';
79+
import { Carousel } from 'uiw';
80+
81+
function Demo() {
82+
83+
const ref=React.useRef()
84+
const [autoPlay,autoPlaySet]=React.useState(true)
85+
86+
return (
87+
<React.Fragment>
88+
<Carousel ref={ref} position={2} autoPlay={autoPlay}>
89+
<div style={{ height: '100%', background: '#1EABCD' }}>
90+
<span>1</span>
91+
</div>
92+
<div style={{ height: '100%', background: '#393b46' }}>
93+
<span>2</span>
94+
</div>
95+
<div style={{ height: '100%', background: '#008EF0' }}>
96+
<span>3</span>
97+
</div>
98+
<div style={{ height: '100%', background: '#393E48' }}>
99+
<span>4</span>
100+
</div>
101+
</Carousel>
102+
<button onClick={() => ref.current.gotoSlide(1)}>跳转</button>
103+
<button onClick={() => ref.current.prevSlide()}>上一张</button>
104+
<button onClick={() => ref.current.nextSlide()}>下一张</button>
105+
<button onClick={() =>autoPlaySet(autoPlay?false:true)}>{autoPlay?'暂停':'开始'}</button>
106+
</React.Fragment>
107+
);
108+
}
109+
110+
ReactDOM.render(<Demo />, _mount_);
111+
```
112+
113+
## Props
114+
115+
## API
116+
117+
| 参数 | 说明 | 类型 | 默认值 |
118+
|--------- |-------- |--------- |-------- |
119+
| width | 宽度 | number | 400 |
120+
| height | 高度 | number | 200 |
121+
| position | 设置初始帧位置 | number | 0 |
122+
| palyTime | 每帧停留时间(ms) | number | 2000 |
123+
| scrollTime | 滚动动画的速度(ms) | number | 200 |
124+
| autoPlay | 是否自动播放 | boolean | true |
125+
126+
127+
### ref
128+
129+
```ts
130+
// 跳转到指定帧
131+
gotoSlide: (slideNumber: number) => void;
132+
// 上一针
133+
prevSlide: () => void;
134+
// 下一帧
135+
nextSlide: () => void;
136+
// 暂停播放
137+
stopPlay: () => void;
138+
```
139+
140+

‎packages/react-carousel/package.json

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
{
2+
"name": "@uiw/react-carousel",
3+
"version": "4.14.2",
4+
"description": "Carousel component",
5+
"homepage": "https://uiwjs.github.io/#/components/carousel",
6+
"repository": {
7+
"type": "git",
8+
"url": "https://github.com/uiwjs/uiw.git"
9+
},
10+
"license": "MIT",
11+
"main": "cjs/index.js",
12+
"module": "esm/index.js",
13+
"files": [
14+
"dist.css",
15+
"cjs",
16+
"esm",
17+
"src"
18+
],
19+
"publishConfig": {
20+
"access": "public"
21+
},
22+
"keywords": [
23+
"carousel",
24+
"design",
25+
"uiw",
26+
"uiw-react",
27+
"react.js",
28+
"react",
29+
"react-component",
30+
"component",
31+
"components",
32+
"ui",
33+
"css",
34+
"uikit",
35+
"react-ui",
36+
"framework",
37+
"front-end",
38+
"frontend"
39+
],
40+
"peerDependencies": {
41+
"react": ">=16.9.0",
42+
"react-dom": ">=16.9.0"
43+
},
44+
"dependencies": {
45+
"@uiw/utils": "^4.14.2"
46+
}
47+
}

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

+103
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import React, { useEffect, useMemo, useRef, useState } from 'react';
2+
import { IProps, HTMLDivProps } from '@uiw/utils';
3+
import './style/index.less';
4+
5+
export interface CarouselProps extends IProps, HTMLDivProps {
6+
width?: number;
7+
height?: number;
8+
position?: number;
9+
palyTime?: number;
10+
scrollTime?: number;
11+
autoPlay?: boolean;
12+
}
13+
14+
export interface CarouselRef {
15+
gotoSlide: (slide: number, dontAnimate?: boolean) => void;
16+
prevSlide: () => void;
17+
nextSlide: () => void;
18+
stopPlay: () => void;
19+
}
20+
21+
function Carousel(props: CarouselProps, ref: CarouselRef) {
22+
const {
23+
position = 0,
24+
width = 400,
25+
height = 200,
26+
palyTime = 2000,
27+
scrollTime = 200,
28+
autoPlay = true,
29+
30+
prefixCls = 'w-carousel',
31+
className,
32+
style,
33+
} = props;
34+
35+
const cls = useMemo(() => [prefixCls, className].filter(Boolean).join(' ').trim(), [prefixCls, className]);
36+
37+
const [currentPosition, currentPositionSet] = useState(position);
38+
const positionRef = useRef(currentPosition);
39+
const childCount = React.Children.count(props.children);
40+
const stopPlay = useRef<Function>(() => {});
41+
42+
React.useImperativeHandle(
43+
ref,
44+
() => ({
45+
gotoSlide,
46+
prevSlide: () => gotoSlide(positionRef.current - 1),
47+
nextSlide: () => gotoSlide(positionRef.current + 1),
48+
stopPlay: () => stopPlay.current(),
49+
}),
50+
[ref],
51+
);
52+
53+
const gotoSlide = (slidNumber: number) => {
54+
stopPlay.current();
55+
const maxSlid = childCount - 1;
56+
let slidNumberTemp = slidNumber > maxSlid ? maxSlid : slidNumber;
57+
slidNumberTemp = slidNumber < 0 ? 0 : slidNumberTemp;
58+
positionRef.current = slidNumberTemp;
59+
currentPositionSet(slidNumberTemp);
60+
play();
61+
};
62+
63+
const play = (ms: number = palyTime) => {
64+
if (autoPlay) {
65+
const time = setInterval(() => {
66+
positionRef.current++;
67+
if (positionRef.current >= childCount) {
68+
positionRef.current = 0;
69+
}
70+
currentPositionSet(positionRef.current);
71+
}, ms);
72+
stopPlay.current = () => {
73+
clearInterval(time);
74+
};
75+
}
76+
};
77+
78+
useEffect(() => {
79+
play();
80+
return () => {
81+
stopPlay.current();
82+
};
83+
}, [autoPlay]);
84+
85+
return (
86+
<div className={cls} style={{ width, height }}>
87+
<div
88+
className={`${cls}-content`}
89+
style={{
90+
width: width * childCount,
91+
transform: `translate3d(${-(currentPosition * width)}px, 0px, 0px)`,
92+
transition: `${scrollTime * 0.001}s ease-in-out`,
93+
}}
94+
>
95+
{React.Children.map(props.children, (child) => {
96+
return <div style={{ width, height, ...style }}>{child}</div>;
97+
})}
98+
</div>
99+
</div>
100+
);
101+
}
102+
103+
export default React.forwardRef<CarouselRef, CarouselProps>(Carousel);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
@w-carousel: ~'w-carousel';
2+
3+
.@{w-carousel} {
4+
overflow: hidden;
5+
6+
&-content {
7+
height: 200px;
8+
// transform: translate3d();
9+
display: flex;
10+
flex-direction: row;
11+
transition: 0.6s ease-in-out;
12+
}
13+
}

‎packages/react-carousel/tsconfig.json

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"extends": "../../tsconfig",
3+
"include": ["src/**/*"],
4+
"compilerOptions": {
5+
"outDir": "./cjs",
6+
"baseUrl": "."
7+
}
8+
}

‎packages/react-transfer/package.json

-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@
4444
"dependencies": {
4545
"@uiw/react-card": "^4.14.2",
4646
"@uiw/react-checkbox": "^4.14.2",
47-
"@uiw/react-grid": "^4.14.2",
4847
"@uiw/react-icon": "^4.14.2",
4948
"@uiw/react-input": "^4.14.2",
5049
"@uiw/react-tree": "^4.14.2",

‎packages/uiw/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
"@uiw/react-button-group": "^4.14.2",
6868
"@uiw/react-calendar": "^4.14.2",
6969
"@uiw/react-card": "^4.14.2",
70+
"@uiw/react-carousel": "^4.14.2",
7071
"@uiw/react-checkbox": "^4.14.2",
7172
"@uiw/react-collapse": "^4.14.2",
7273
"@uiw/react-copy-to-clipboard": "^4.14.2",

‎packages/uiw/src/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export * from '@uiw/react-button';
99
export * from '@uiw/react-button-group';
1010
export * from '@uiw/react-calendar';
1111
export * from '@uiw/react-card';
12+
export * from '@uiw/react-carousel';
1213
export * from '@uiw/react-checkbox';
1314
export * from '@uiw/react-collapse';
1415
export * from '@uiw/react-copy-to-clipboard';
@@ -69,6 +70,7 @@ export { default as Button } from '@uiw/react-button';
6970
export { default as ButtonGroup } from '@uiw/react-button-group';
7071
export { default as Calendar } from '@uiw/react-calendar';
7172
export { default as Card } from '@uiw/react-card';
73+
export { default as Carousel } from '@uiw/react-carousel';
7274
export { default as Checkbox } from '@uiw/react-checkbox';
7375
export { default as Collapse } from '@uiw/react-collapse';
7476
export { default as CopyToClipboard } from '@uiw/react-copy-to-clipboard';

‎website/src/menu.json

+1
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
{ "name": "Avatar 头像", "path": "avatar" },
7171
{ "name": "Badge 标记", "path": "badge" },
7272
{ "name": "Card 卡片", "path": "card" },
73+
{ "name": "Carousel 走马灯", "path": "carousel" },
7374
{ "name": "Collapse 折叠面板", "path": "collapse" },
7475
{ "name": "Descriptions 描述列表", "path": "descriptions" },
7576
{ "name": "Tag 标签", "path": "tag" },

‎website/src/routers.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ const Checkbox = Loadable(lazy(() => import('./routes/components/checkbox')));
3434
const CopyToClipboard = Loadable(lazy(() => import('./routes/components/copy-to-clipboard')));
3535
const Collapse = Loadable(lazy(() => import('./routes/components/collapse')));
3636
const Card = Loadable(lazy(() => import('./routes/components/card')));
37+
const Carousel = Loadable(lazy(() => import('./routes/components/carousel')));
3738
const Descriptions = Loadable(lazy(() => import('./routes/components/descriptions')));
3839
const Loader = Loadable(lazy(() => import('./routes/components/loader')));
3940
const Icon = Loadable(lazy(() => import('./routes/components/icon')));
@@ -126,6 +127,7 @@ export const routes: RouteObject[] = [
126127
{ path: '/components/copy-to-clipboard', element: <CopyToClipboard /> },
127128
{ path: '/components/collapse', element: <Collapse /> },
128129
{ path: '/components/card', element: <Card /> },
130+
{ path: '/components/carousel', element: <Carousel /> },
129131
{ path: '/components/descriptions', element: <Descriptions /> },
130132
{ path: '/components/loader', element: <Loader /> },
131133
{ path: '/components/icon', element: <Icon /> },
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import React from 'react';
2+
import { Carousel, Row, Col } from 'uiw';
3+
import Markdown from '../../../components/Markdown';
4+
5+
export default function Page() {
6+
return (
7+
<Markdown
8+
path="https://github.com/uiwjs/uiw/tree/master/packages/react-carousel/README.md"
9+
dependencies={{ Carousel, React, Row, Col }}
10+
renderPage={async () => {
11+
const md = await import('uiw/node_modules/@uiw/react-carousel/README.md');
12+
return md.default || md;
13+
}}
14+
/>
15+
);
16+
}

‎website/src/routes/components/transfer/index.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import Markdown from '../../../components/Markdown';
44

55
export default () => (
66
<Markdown
7-
path="https://github.com/uiwjs/uiw/tree/master/packages/react-search-tree/README.md"
7+
path="https://github.com/uiwjs/uiw/tree/master/packages/react-transfer/README.md"
88
dependencies={{ Form, Button, TreeChecked, Transfer, Row, Col, Card, Icon, React }}
99
renderPage={async () => {
1010
const md = await import('uiw/node_modules/@uiw/react-transfer/README.md');

0 commit comments

Comments
 (0)
Please sign in to comment.