diff --git a/components/carousel/index.js b/components/carousel/index.js new file mode 100644 index 000000000..c35fd31e5 --- /dev/null +++ b/components/carousel/index.js @@ -0,0 +1,177 @@ +import React, { Component } from 'react' +import PropTypes from 'prop-types' +import Icon from '../icon' +import classNames from 'classnames' +import './style/index' + +// const url = 'http://i1.mifile.cn/f/i/hiui/docs/' +class Carousel extends Component { + constructor (props) { + super(props) + this.rootRef = React.createRef() + const defaultActive = props.defaultActive + this.state = { + rootWidth: 0, + showArrow: false, + active: (defaultActive >= props.children.length || defaultActive < 0) ? 0 : defaultActive + } + this.timer = null + } + + componentDidMount () { + this.setState({ + rootWidth: this.rootRef.current.clientWidth + }, () => { + if (this.props.duration) { + this.autoPage() + } + }) + } + + goTo (page) { + if (page > this.props.children.length || page < 0) { + return + } + this.setState({ + active: page + }) + } + componentWillUnmount () { + this.timer && window.clearInterval(this.timer) + } + + autoPage () { + this.timer = window.setInterval(() => { + this.preNextEvent(1) + }, this.props.duration) + } + + pageEvent (active) { + this.setState({ + active + }) + } + + preNextEvent (val) { + let active = this.state.active + val + if (active >= this.props.children.length) { + active = 0 + } + this.setState({ + active + }) + } + + renderDot (type, key, index, active) { + if (type === 'sign') { + return
  • + } else { + const cls = classNames( + 'hi-carousel__dot', + active === index && 'hi-carousel__dot--active' + ) + return ( +
  • + ) + } + } + + mouseEvent (type) { + let showArrow = true + if (type === 'over') { + this.timer && window.clearInterval(this.timer) + } else { + showArrow = false + this.props.duration && this.autoPage() + } + this.setState({showArrow}) + } + render () { + const { rootWidth, active, showArrow } = this.state + const { showDots, showArrows } = this.props + const children = React.Children.toArray(this.props.children) + const arrowCls = classNames( + 'hi-carousel__arrows', + showArrow && 'hi-carousel__arrows--show' + ) + return
    +
    + { + children.map((child, index) => { + return React.cloneElement(child, { + key: index, + style: { + position: 'relative', + opacity: active === index ? 1 : 0, + transition: 'opacity 300ms ease 0s', + left: -(rootWidth * index), + width: rootWidth, + display: 'inline-block', + fontSize: 24, + ...child.props.style + } + }) + }) + } +
    + { + showArrows && + } + { + showDots && + } +
    + } +} + +Carousel.propTypes = { + duration: PropTypes.number, + onClick: PropTypes.func, + beforeChange: PropTypes.func, + afterChange: PropTypes.func, + showDots: PropTypes.bool, + showArrows: PropTypes.bool, + defaultActive: PropTypes.number +} +Carousel.defaultProps = { + duration: 0, + onClick: () => {}, + beforeChange: () => {}, + afterChange: () => {}, + showDots: true, + showArrows: true, + defaultActive: 0 +} + +export default Carousel diff --git a/components/carousel/style/index.js b/components/carousel/style/index.js new file mode 100644 index 000000000..63810a681 --- /dev/null +++ b/components/carousel/style/index.js @@ -0,0 +1 @@ +import './index.scss' diff --git a/components/carousel/style/index.scss b/components/carousel/style/index.scss new file mode 100644 index 000000000..cf049545b --- /dev/null +++ b/components/carousel/style/index.scss @@ -0,0 +1,74 @@ +.hi-carousel { + width: 100%; + color: rgba(153, 153, 153, 1); + overflow: hidden; + position: relative; + + &__container { + height: 100%; + transition: all 500ms; + } + + &__dots { + position: absolute; + bottom: 24px; + margin: 0; + padding: 0; + left: 50%; + transform: translateX(-50%); + } + + &__dot { + width: 24px; + height: 4px; + background: rgba(255, 255, 255, 0.4); + border-radius: 2px; + display: inline-block; + margin-left: 4px; + cursor: pointer; + transition: all 1s; + + &--active:not(.hi-carousel__dot--sign) { + background: rgba(255, 255, 255, 1); + width: 48px; + } + + &--sign { + width: 24px; + } + } + + &__arrows { + position: absolute; + width: 100%; + list-style: none; + margin: 0; + padding: 0; + top: 50%; + transform: translateY(-28px); + display: flex; + justify-content: space-between; + visibility: hidden; + + &--show { + visibility: visible; + } + } + + &__arrow { + width: 56px; + height: 56px; + background: rgba(0, 0, 0, 0.25); + border-radius: 50%; + text-align: center; + line-height: 56px; + color: #fff; + font-size: 32px; + margin-left: 24px; + cursor: pointer; + + &:last-child { + margin-right: 24px; + } + } +} diff --git a/components/index.js b/components/index.js index 823896e3c..51ee73cd2 100755 --- a/components/index.js +++ b/components/index.js @@ -42,4 +42,5 @@ export { default as Rate } from './rate' export { default as Message } from './message' export { default as Tag } from './tag' export { default as Breadcrumb } from './breadcrumb' +export { default as Carousel } from './carousel' export { ThemeContext, LocaleContext } from './context' diff --git a/docs/demo/breadcrumb/section-base.jsx b/docs/demo/breadcrumb/section-base.jsx index 4a7f39e5f..a8dc191ef 100644 --- a/docs/demo/breadcrumb/section-base.jsx +++ b/docs/demo/breadcrumb/section-base.jsx @@ -3,7 +3,7 @@ import DocViewer from '../../../libs/doc-viewer' import Breadcrumb from '../../../components/breadcrumb' const prefix = 'alert-base' const code = `import React from 'react' -import Alert from '@hi-ui/hiui/es/alert'\n +import Breadcrumb from '@hi-ui/hiui/es/breadcrumb'\n class Demo extends React.Component { render () { const data = [{ diff --git a/docs/demo/carousel/section-base.jsx b/docs/demo/carousel/section-base.jsx new file mode 100644 index 000000000..f0470c742 --- /dev/null +++ b/docs/demo/carousel/section-base.jsx @@ -0,0 +1,31 @@ +import React from 'react' +import DocViewer from '../../../libs/doc-viewer' +import Carousel from '../../../components/carousel' +const prefix = 'carousel-base' +const code = `import React from 'react' +import Carousel from '@hi-ui/hiui/es/carousel'\n +class Demo extends React.Component { + constructor (props) { + super(props) + } + + render () { + const data = [1, 2, 3, 4, 5, 6, 7, 8, 9] + return ( +
    + + { + data.map((item) => { + return
    {item}
    + }) + } +
    +
    + ) + } +}` + +const DemoBase = () => +export default DemoBase diff --git a/docs/demo/carousel/section-icon.jsx b/docs/demo/carousel/section-icon.jsx new file mode 100644 index 000000000..5ab0544a3 --- /dev/null +++ b/docs/demo/carousel/section-icon.jsx @@ -0,0 +1,27 @@ +import React from 'react' +import DocViewer from '../../../libs/doc-viewer' +import Carousel from '../../../components/carousel' +const prefix = 'carousel-base' +const code = `import React from 'react' +import Carousel from '@hi-ui/hiui/es/carousel'\n +class Demo extends React.Component { + render () { + const data = [1, 2, 3, 4, 5, 6, 7, 8] + return ( +
    + + { + data.map((item, index) => { + return + }) + } + +
    + ) + } +}` + +const DemoBase = () => +export default DemoBase diff --git a/docs/zh-CN/components/carousel.mdx b/docs/zh-CN/components/carousel.mdx new file mode 100644 index 000000000..f5dc47f3d --- /dev/null +++ b/docs/zh-CN/components/carousel.mdx @@ -0,0 +1,22 @@ +# Carousel 走马灯 + +## 基础用法 + +import DemoBase from '../../demo/carousel/section-base.jsx' + + + +## 图片展示 + +import DemoImage from '../../demo/carousel/section-icon.jsx' + + + +## Props + +| 参数 | 说明 | 类型 | 可选值 | 默认值 | +| -------------- | ------------------------------------------------- | --------------------------- | ------------- | ------------------------------------------------------- | +| duration | 自动切换间隔,默认不自动切换 | number | - | 0 | +| showDots | 是否显示分页指示器 | boolean | - | false | +| showArrows | 是否显示箭头指示器 | boolean | - | false | +| defaultActive | 默认激活索引,从0开始 | number | - | 0 | diff --git a/site/locales/zh-CN.js b/site/locales/zh-CN.js index 2ba8da091..b2e923332 100755 --- a/site/locales/zh-CN.js +++ b/site/locales/zh-CN.js @@ -51,7 +51,8 @@ module.exports = { transfer: 'Transfer 穿梭框', switch: 'Switch 开关', rate: 'Rate 评分', - breadcrumb: 'Breadcrumb 面包屑' + breadcrumb: 'Breadcrumb 面包屑', + carousel: 'Carousel 走马灯' }, designs: { summarize: '概述', diff --git a/site/pages/components/index.js b/site/pages/components/index.js index 1581ea15a..cbcaf03a3 100755 --- a/site/pages/components/index.js +++ b/site/pages/components/index.js @@ -51,7 +51,8 @@ export default { popover: components['popover'], progress: components['progress'], card: components['card'], - timeline: components['timeline'] + timeline: components['timeline'], + carousel: components['carousel'] }, 'group-tips': { modal: components['modal'],