Skip to content

Commit

Permalink
faeat(Carousel): 增加走马灯组件Carousel (#691)
Browse files Browse the repository at this point in the history
  • Loading branch information
nullptr-z committed Mar 19, 2022
1 parent 1a6768e commit 4723874
Show file tree
Hide file tree
Showing 14 changed files with 344 additions and 2 deletions.
5 changes: 5 additions & 0 deletions .github/workflows/deploy.yml
Expand Up @@ -123,6 +123,11 @@ jobs:
with:
token: ${{ secrets.NPM_TOKEN }}
package: ./packages/react-card/package.json
- name: 📦 @uiw/react-carousel publish to NPM
uses: JS-DevTools/npm-publish@v1
with:
token: ${{ secrets.NPM_TOKEN }}
package: ./packages/react-carousel/package.json
- name: 📦 @uiw/react-checkbox publish to NPM
uses: JS-DevTools/npm-publish@v1
with:
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/npm.yml
Expand Up @@ -192,6 +192,11 @@ jobs:
with:
token: ${{ secrets.NPM_TOKEN }}
package: ./packages/react-card/package.json
- name: 📦 @uiw/react-carousel publish to NPM
uses: JS-DevTools/npm-publish@v1
with:
token: ${{ secrets.NPM_TOKEN }}
package: ./packages/react-carousel/package.json
- name: 📦 @uiw/react-checkbox publish to NPM
uses: JS-DevTools/npm-publish@v1
with:
Expand Down
140 changes: 140 additions & 0 deletions packages/react-carousel/README.md
@@ -0,0 +1,140 @@
Carousel 走马灯
===

[![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)
[![NPM Downloads](https://img.shields.io/npm/dm/@uiw/react-carousel.svg?style=flat)](https://www.npmjs.com/package/@uiw/react-carousel)
[![npm version](https://img.shields.io/npm/v/@uiw/react-carousel.svg?label=@uiw/react-carousel)](https://npmjs.com/@uiw/react-carousel)

滚动播放。在 v4.15.0+ 添加。

## 基础用法

最简单的用法。

<!--rehype:bgWhite=true&codeSandbox=true&codePen=true-->
```jsx
import React from 'react';
import { Carousel } from 'uiw';

function Demo() {
return (
<Carousel>
<div style={{ height: '100%', background: '#1EABCD' }}>
<span>1</span>
</div>
<div style={{ height: '100%', background: '#393b46' }}>
<span>2</span>
</div>
<div style={{ height: '100%', background: '#008EF0' }}>
<span>3</span>
</div>
<div style={{ height: '100%', background: '#393E48' }}>
<span>4</span>
</div>
</Carousel>
);
}

ReactDOM.render(<Demo />, _mount_);
```

## 控制播放频率

palyTime设置每帧停留时间,scrollTime设置切换帧的速度

<!--rehype:bgWhite=true&codeSandbox=true&codePen=true-->
```jsx
import React from 'react';
import { Carousel } from 'uiw';

function Demo() {
return (
<Carousel palyTime={1000} scrollTime={500}>
<div style={{ height: '100%', background: '#1EABCD' }}>
<span>1</span>
</div>
<div style={{ height: '100%', background: '#393b46' }}>
<span>2</span>
</div>
<div style={{ height: '100%', background: '#008EF0' }}>
<span>3</span>
</div>
<div style={{ height: '100%', background: '#393E48' }}>
<span>4</span>
</div>
</Carousel>
);
}

ReactDOM.render(<Demo />, _mount_);
```

## 切换到指定帧

手动切换到指定帧的位置

<!--rehype:bgWhite=true&codeSandbox=true&codePen=true-->
```jsx
import React from 'react';
import { Carousel } from 'uiw';

function Demo() {

const ref=React.useRef()
const [autoPlay,autoPlaySet]=React.useState(true)

return (
<React.Fragment>
<Carousel ref={ref} position={2} autoPlay={autoPlay}>
<div style={{ height: '100%', background: '#1EABCD' }}>
<span>1</span>
</div>
<div style={{ height: '100%', background: '#393b46' }}>
<span>2</span>
</div>
<div style={{ height: '100%', background: '#008EF0' }}>
<span>3</span>
</div>
<div style={{ height: '100%', background: '#393E48' }}>
<span>4</span>
</div>
</Carousel>
<button onClick={() => ref.current.gotoSlide(1)}>跳转</button>
<button onClick={() => ref.current.prevSlide()}>上一张</button>
<button onClick={() => ref.current.nextSlide()}>下一张</button>
<button onClick={() =>autoPlaySet(autoPlay?false:true)}>{autoPlay?'暂停':'开始'}</button>
</React.Fragment>
);
}

ReactDOM.render(<Demo />, _mount_);
```

## Props

## API

| 参数 | 说明 | 类型 | 默认值 |
|--------- |-------- |--------- |-------- |
| width | 宽度 | number | 400 |
| height | 高度 | number | 200 |
| position | 设置初始帧位置 | number | 0 |
| palyTime | 每帧停留时间(ms) | number | 2000 |
| scrollTime | 滚动动画的速度(ms) | number | 200 |
| autoPlay | 是否自动播放 | boolean | true |


### ref

```ts
// 跳转到指定帧
gotoSlide: (slideNumber: number) => void;
// 上一针
prevSlide: () => void;
// 下一帧
nextSlide: () => void;
// 暂停播放
stopPlay: () => void;
```


47 changes: 47 additions & 0 deletions packages/react-carousel/package.json
@@ -0,0 +1,47 @@
{
"name": "@uiw/react-carousel",
"version": "4.14.2",
"description": "Carousel component",
"homepage": "https://uiwjs.github.io/#/components/carousel",
"repository": {
"type": "git",
"url": "https://github.com/uiwjs/uiw.git"
},
"license": "MIT",
"main": "cjs/index.js",
"module": "esm/index.js",
"files": [
"dist.css",
"cjs",
"esm",
"src"
],
"publishConfig": {
"access": "public"
},
"keywords": [
"carousel",
"design",
"uiw",
"uiw-react",
"react.js",
"react",
"react-component",
"component",
"components",
"ui",
"css",
"uikit",
"react-ui",
"framework",
"front-end",
"frontend"
],
"peerDependencies": {
"react": ">=16.9.0",
"react-dom": ">=16.9.0"
},
"dependencies": {
"@uiw/utils": "^4.14.2"
}
}
103 changes: 103 additions & 0 deletions packages/react-carousel/src/index.tsx
@@ -0,0 +1,103 @@
import React, { useEffect, useMemo, useRef, useState } from 'react';
import { IProps, HTMLDivProps } from '@uiw/utils';
import './style/index.less';

export interface CarouselProps extends IProps, HTMLDivProps {
width?: number;
height?: number;
position?: number;
palyTime?: number;
scrollTime?: number;
autoPlay?: boolean;
}

export interface CarouselRef {
gotoSlide: (slide: number, dontAnimate?: boolean) => void;
prevSlide: () => void;
nextSlide: () => void;
stopPlay: () => void;
}

function Carousel(props: CarouselProps, ref: CarouselRef) {
const {
position = 0,
width = 400,
height = 200,
palyTime = 2000,
scrollTime = 200,
autoPlay = true,

prefixCls = 'w-carousel',
className,
style,
} = props;

const cls = useMemo(() => [prefixCls, className].filter(Boolean).join(' ').trim(), [prefixCls, className]);

const [currentPosition, currentPositionSet] = useState(position);
const positionRef = useRef(currentPosition);
const childCount = React.Children.count(props.children);
const stopPlay = useRef<Function>(() => {});

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

const gotoSlide = (slidNumber: number) => {
stopPlay.current();
const maxSlid = childCount - 1;
let slidNumberTemp = slidNumber > maxSlid ? maxSlid : slidNumber;
slidNumberTemp = slidNumber < 0 ? 0 : slidNumberTemp;
positionRef.current = slidNumberTemp;
currentPositionSet(slidNumberTemp);
play();
};

const play = (ms: number = palyTime) => {
if (autoPlay) {
const time = setInterval(() => {
positionRef.current++;
if (positionRef.current >= childCount) {
positionRef.current = 0;
}
currentPositionSet(positionRef.current);
}, ms);
stopPlay.current = () => {
clearInterval(time);
};
}
};

useEffect(() => {
play();
return () => {
stopPlay.current();
};
}, [autoPlay]);

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`,
}}
>
{React.Children.map(props.children, (child) => {
return <div style={{ width, height, ...style }}>{child}</div>;
})}
</div>
</div>
);
}

export default React.forwardRef<CarouselRef, CarouselProps>(Carousel);
13 changes: 13 additions & 0 deletions packages/react-carousel/src/style/index.less
@@ -0,0 +1,13 @@
@w-carousel: ~'w-carousel';

.@{w-carousel} {
overflow: hidden;

&-content {
height: 200px;
// transform: translate3d();
display: flex;
flex-direction: row;
transition: 0.6s ease-in-out;
}
}
8 changes: 8 additions & 0 deletions packages/react-carousel/tsconfig.json
@@ -0,0 +1,8 @@
{
"extends": "../../tsconfig",
"include": ["src/**/*"],
"compilerOptions": {
"outDir": "./cjs",
"baseUrl": "."
}
}
1 change: 0 additions & 1 deletion packages/react-transfer/package.json
Expand Up @@ -44,7 +44,6 @@
"dependencies": {
"@uiw/react-card": "^4.14.2",
"@uiw/react-checkbox": "^4.14.2",
"@uiw/react-grid": "^4.14.2",
"@uiw/react-icon": "^4.14.2",
"@uiw/react-input": "^4.14.2",
"@uiw/react-tree": "^4.14.2",
Expand Down
1 change: 1 addition & 0 deletions packages/uiw/package.json
Expand Up @@ -67,6 +67,7 @@
"@uiw/react-button-group": "^4.14.2",
"@uiw/react-calendar": "^4.14.2",
"@uiw/react-card": "^4.14.2",
"@uiw/react-carousel": "^4.14.2",
"@uiw/react-checkbox": "^4.14.2",
"@uiw/react-collapse": "^4.14.2",
"@uiw/react-copy-to-clipboard": "^4.14.2",
Expand Down
2 changes: 2 additions & 0 deletions packages/uiw/src/index.ts
Expand Up @@ -9,6 +9,7 @@ export * from '@uiw/react-button';
export * from '@uiw/react-button-group';
export * from '@uiw/react-calendar';
export * from '@uiw/react-card';
export * from '@uiw/react-carousel';
export * from '@uiw/react-checkbox';
export * from '@uiw/react-collapse';
export * from '@uiw/react-copy-to-clipboard';
Expand Down Expand Up @@ -69,6 +70,7 @@ export { default as Button } from '@uiw/react-button';
export { default as ButtonGroup } from '@uiw/react-button-group';
export { default as Calendar } from '@uiw/react-calendar';
export { default as Card } from '@uiw/react-card';
export { default as Carousel } from '@uiw/react-carousel';
export { default as Checkbox } from '@uiw/react-checkbox';
export { default as Collapse } from '@uiw/react-collapse';
export { default as CopyToClipboard } from '@uiw/react-copy-to-clipboard';
Expand Down
1 change: 1 addition & 0 deletions website/src/menu.json
Expand Up @@ -70,6 +70,7 @@
{ "name": "Avatar 头像", "path": "avatar" },
{ "name": "Badge 标记", "path": "badge" },
{ "name": "Card 卡片", "path": "card" },
{ "name": "Carousel 走马灯", "path": "carousel" },
{ "name": "Collapse 折叠面板", "path": "collapse" },
{ "name": "Descriptions 描述列表", "path": "descriptions" },
{ "name": "Tag 标签", "path": "tag" },
Expand Down
2 changes: 2 additions & 0 deletions website/src/routers.tsx
Expand Up @@ -34,6 +34,7 @@ const Checkbox = Loadable(lazy(() => import('./routes/components/checkbox')));
const CopyToClipboard = Loadable(lazy(() => import('./routes/components/copy-to-clipboard')));
const Collapse = Loadable(lazy(() => import('./routes/components/collapse')));
const Card = Loadable(lazy(() => import('./routes/components/card')));
const Carousel = Loadable(lazy(() => import('./routes/components/carousel')));
const Descriptions = Loadable(lazy(() => import('./routes/components/descriptions')));
const Loader = Loadable(lazy(() => import('./routes/components/loader')));
const Icon = Loadable(lazy(() => import('./routes/components/icon')));
Expand Down Expand Up @@ -126,6 +127,7 @@ export const routes: RouteObject[] = [
{ path: '/components/copy-to-clipboard', element: <CopyToClipboard /> },
{ path: '/components/collapse', element: <Collapse /> },
{ path: '/components/card', element: <Card /> },
{ path: '/components/carousel', element: <Carousel /> },
{ path: '/components/descriptions', element: <Descriptions /> },
{ path: '/components/loader', element: <Loader /> },
{ path: '/components/icon', element: <Icon /> },
Expand Down

0 comments on commit 4723874

Please sign in to comment.