react 實現一個無限循環的輪播器 附github地址
阿新 • • 發佈:2018-12-28
class 不為 cursor oot rect 動畫 參數類型 4.0 z-index
一個簡單的輪播
為了更具有通用和參考性,輪播組件中,輪播只使用了react,沒有添加其他的狀態管理,或者參數類型限制的庫.
github地址
最終效果
顯示無限循環原理
如圖所示,如果輪播裏面有三個部分,那麽可以在首端前添加一個跟最後一塊一樣的dom節點,同理在最末端添加跟首端相同的節點,這樣當輪播到末端,在下一張的情況下,就可以無縫銜接首端的節點,然後當動畫結束後,在直接切換到真正的首端,就實現了無縫銜接的輪播器
組件代碼
import React, {Component} from ‘react‘; import style from ‘./style.use.less‘; export default class Test extends Component { static defaultProps = { step: 2000, animationStep: 1 } constructor(props) { super(props) this.state = { currentCarousel: 0, translateList: [], animationStep: 0, } this.handleCarouselBodyMouseOver = this.handleCarouselBodyMouseOver.bind(this); this.handleCarouselBodyMouseOut = this.handleCarouselBodyMouseOut.bind(this); this.handleCarouselFooterMouseOver = this.handleCarouselFooterMouseOver.bind(this); this.renderIndicators = this.renderIndicators.bind(this); this.getIndicatorsActive = this.getIndicatorsActive.bind(this); this.handlerNext = this.handlerNext.bind(this); this.handlerTransitionEnd = this.handlerTransitionEnd.bind(this); this.handlerPre = this.handlerPre.bind(this); } componentWillMount() { style.use() } componentWillUnmount() { style.unuse() this.stopCarousel() } componentDidMount() { this.setState({ animationStep: this.props.animationStep }) this.startCarousel() } /** * @description 開始輪播 */ startCarousel() { this.stopCarousel() this.timerID = setInterval(() => { console.log(this.state.currentCarousel) this.handlerCarousel() }, this.props.step ); } /** * @description 更改當前循環到的輪播下標 * @param {String} type 運動的方向類型 */ handlerCarousel(type) { let direction = 1; if (type === ‘left‘) { // 向做運動 下標減1 direction = -1; } if (this.state.currentCarousel % (this.props.children.length + 1) !== this.props.children.length && this.state.currentCarousel >= 0) { // 下標不為-1 或者最後一項的情況下正常 遞增或者遞減 this.setState(pre => { pre.currentCarousel += direction; return { animationStep: this.props.animationStep, // 運動動畫 設置值 因為 當坐標在邊界的時候 會取消動畫時間 所以在不為邊界的時候 要恢復動畫時間 不然切換無輪播動畫 currentCarousel: pre.currentCarousel % (this.props.children.length + 1) } }) } } /** * @description 監聽動畫結束 在下標為邊界時 並且切換的動畫結束 取消動畫 並調整輪播位置 */ handlerTransitionEnd() { // 當在最末端的時候 取消動畫 並將坐標重制為0 if (this.state.currentCarousel % (this.props.children.length + 1) === this.props.children.length) { this.setState(pre => { return { animationStep: 0, currentCarousel: 0, } }) } // 當在最前端的時候 取消動畫 並將坐標重制為最大 else if (this.state.currentCarousel < 0) { this.setState(pre => { return { animationStep: 0, currentCarousel: this.props.children.length - 1, } }) } } /** * @description 停止輪播 */ stopCarousel() { clearInterval(this.timerID); } /** * @description 指示按鈕的mouseover事件 */ handleCarouselFooterMouseOver(currentIndex) { this.setState({ currentCarousel: currentIndex }); } /** * @description 輪播的mouseover事件 */ handleCarouselBodyMouseOver() { this.stopCarousel(); } /** * @description 輪播的mouseout事件 */ handleCarouselBodyMouseOut() { this.startCarousel(); } /** * @description 輪播的mouseout事件 */ handlerNext() { this.handlerCarousel(‘right‘); } handlerPre() { this.handlerCarousel(‘left‘); } getIndicatorsActive(index) { let active; // 邊界判斷 使在輪播在邊界的時候 導航下面的小標 也能正常的添加active狀態 if (this.state.currentCarousel === index || this.state.currentCarousel === index + this.props.children.length || this.state.currentCarousel < 0 && index === this.props.children.length - 1) { return ‘active‘; } return ‘‘ } /** * @description 導航的指示按鈕 */ renderIndicators() { return ( <div className = ‘carousel-footer‘> <ul className = ‘indicators-container‘> {this.props.children.map((item, index) => { let active = this.getIndicatorsActive(index) return <li onMouseOver = {() => this.handleCarouselFooterMouseOver(index)} className = {`indicators-item ${active}`} key = {index} ></li> })} </ul> </div> ) } render() { return( <div className = ‘carousel-container‘ onMouseOver = {this.handleCarouselBodyMouseOver} onMouseOut = {this.handleCarouselBodyMouseOut}> <div className = ‘carousel-body‘ onTransitionEnd = {this.handlerTransitionEnd} style = {{transition: `transform ${this.state.animationStep}s`,width: `${(this.props.children.length+2)*100}%`, transform: `translateX(${-100/(this.props.children.length+2)*(this.state.currentCarousel+1)}%)`}}> <div className = {`carousel-item`} style = {{width: `${100/(this.props.children.length+2)}%`}} key = {‘strat‘} >{this.props.children[this.props.children.length-1]}</div> {this.props.children.map((item, index) => { return <div className = {`carousel-item`} style = {{width: `${100/(this.props.children.length+2)}%`}} key = {index} >{item}</div> })} <div className = {`carousel-item`} style = {{width: `${100/(this.props.children.length+2)}%`}} key = {‘end‘} >{this.props.children[0]}</div> </div> {this.renderIndicators()} <div className = ‘btn-container‘> <div className = ‘btn-direction pre‘ onClick = {this.handlerPre}>{‘<‘}</div> <div className = ‘btn-direction next‘ onClick = {this.handlerNext}>{‘>‘}</div> </div> </div> ) } }
組件csss
.carousel-container { position: relative; width: 100%; height: 100%; overflow: hidden; .carousel-body { height: 100%; .carousel-item { display: inline-block; width: 100%; height: 100%; } } .carousel-footer { position: absolute; width: 100%; bottom: 0; .indicators-container { text-align: center; padding: 0; .indicators-item { list-style: none; display: inline-block; opacity: .48; width: 30px; height: 2px; background-color: #fff; border: none; outline: none; padding: 0; margin: 0; cursor: pointer; transition: .3s; margin: 0 4px; &.active { opacity: 1; } } } } .btn-container { position: absolute; width: 100%; top: 50%; transform: translateY(-50%); .btn-direction { padding: 0; margin: 0; height: 42px; line-height: 38px; width: 36px; cursor: pointer; transition: .3s; border-radius: 50%; background-color: rgba(31,45,61,.11); color: #fff; top: 50%; z-index: 10; text-align: center; font-size: 12px; display: inline-block; position: absolute; top: 50%; transform: translateY(-50%); opacity: 0; } .pre { left: 12px; } .next { right: 12px; } } } .carousel-container:hover .btn-direction{ opacity: 1; &.pre { left: 24px; } &.next { right: 24px; } }
最終調用
import React, {Component} from ‘react‘; import style from ‘./style.use.less‘ import Carouse from ‘../../components/Carousel/Carousel‘ export default class Test extends Component { componentWillMount() { style.use() } componentWillUnmount() { style.unuse() } render() { return ( <div className = ‘carouse‘> <Carouse> <div className = ‘box‘>1</div> <div className = ‘box‘>2</div> <div className = ‘box‘>3</div> <div className = ‘box‘>4</div> </Carouse> </div> ) } }
react 實現一個無限循環的輪播器 附github地址