Slider - 轮播图

2017-11-09  本文已影响0人  WillLi

简介:

用react开发的轮播图组件,支持淡入淡出、水平滚动、垂直滚动的无缝轮播效果。可自定义轮播内容。

API

参数 作用 必传 数值 默认值 备注
type 轮播模式 opacity淡入淡出,moveHorizontal横向移动,moveVertical纵向移动 moveHorizontal opacity类型暂不支持自定义轮播内容
data 需要渲染的数据 单标签需要传,双标签不需要传 [ ]
stepWidth 每屏切换的宽度(px) 1200
showItemNum 每屏显示的个体数量 1
intervalTime 每屏切换的时间间隔(ms) 3000
autoRun 自动播放 left向左,right向右,up向上,down向下,不写或者false禁止自动播放 禁止 left、right对应moveHorizontal,up、down对应moveVertical
hoverStop 鼠标悬浮时,是否停止播放 true悬浮停止,不写或者false悬浮不停止 悬浮时不停止
point 底部是否显示轮播进度 true显示,false隐藏 true

示例1.默认轮播

import Slider from '../../../../../plugin/component/Slider/Slider'
...
<div className='slider-box'>
     <Slider
        type='opacity' 
        data={sliderData}
        stepWidth={960}
        showItemNum={1} 
        intervalTime={4000} 
        autoRun='right' 
        hoverStop={true} 
        point  />
</div>
企业微信截图_15102163287693.png

示例2.自定义轮播

import Slider from '../../../../../plugin/component/Slider/Slider'
...
<div className='slider-box'>
     <Slider stepWidth={960} >
        {
              sliderData2.map((item, index) => {
                return (
                  <li>
                    <a href={item.href} target='_blank'>
                      <img src={item.img} alt={item.alt} />
                    </a>
                  </li>
                )
              })
            }
    </Slider>
</div>
企业微信截图_15102163581813.png

目录结构:

企业微信截图_15102145191107.png

文件说明:

1.Slider.js 入口文件

import SliderMove from './src/SliderMove'
import SliderOpacity from './src/SliderOpacity'

class Slider extends React.Component {
  render () {
    let {type} = this.props
    return type === 'opacity'
      ? <SliderOpacity {...this.props} />
      : <SliderMove {...this.props} />
  }
}
export default Slider

2.SliderMove.js 横向 / 纵向滚动

import './slider.less'
class SliderMove extends React.Component {
  constructor (props) {
    super(props)
    this.sliderInterval = null
    this.state = {
      sliderIndex: 1,
      thisMoveOver: true// 本次轮播是否结束,未结束前,不可进行下次操作
    }
  }
  moveEnd () {
    let {showItemNum} = this.props
    let len = this.props.children || this.props.data
    let thisIndex = this.state.sliderIndex
    if (thisIndex > Math.ceil(len.length / showItemNum)) {
      this.sliderList.style.transition = 'none'
      this.sliderList.style.webkitTransition = 'none'
      this.setState({
        sliderIndex: 1
      })
    }
    if (thisIndex <= 0) {
      this.sliderList.style.transition = 'none'
      this.sliderList.style.webkitTransition = 'none'
      this.setState({
        sliderIndex: Math.ceil(len.length / showItemNum)
      })
    }
    console.log(1)
    this.setState({thisMoveOver: true})
  }
  // 向左
  turnLeftHandle () {
    console.log(this.state.thisMoveOver)
    if (this.state.thisMoveOver) {
      this.sliderList.style.transition = 'all 0.5s linear'
      this.setState((preState, props) => ({
        sliderIndex: preState.sliderIndex + 1,
        thisMoveOver: false
      }))
    }
  }
  // 向右
  turnRightHandle () {
    if (this.state.thisMoveOver) {
      this.sliderList.style.transition = 'all 0.5s linear'
      this.setState((preState, props) => ({
        sliderIndex: preState.sliderIndex - 1,
        thisMoveOver: false
      }))
    }
  }
  // 清除定时器
  clearSliderInterval () {
    clearInterval(this.sliderInterval)
  }
  // 重新开始定时器
  startSliderInterval () {
    let {autoRun, intervalTime} = this.props
    if (autoRun !== undefined && autoRun !== false) {
      this.clearSliderInterval()
      this.sliderInterval = setInterval(() => {
        switch (autoRun) {
          case 'right':
          case 'down':
            this.turnRightHandle()
            break
          case 'left':
          case 'up':
            this.turnLeftHandle()
            break
          default:
            return false
        }
      }, intervalTime)
    }
  }
  // 判断用户是否正在浏览当前页面
  onVisibilityChanged (e) {
    let hidden = e.target.hidden
    if (hidden) {
      clearInterval(this.sliderInterval)
    } else {
      this.startSliderInterval()
    }
  }
  componentDidMount () {
    this.sliderList.addEventListener('transitionend', this.moveEnd.bind(this, 0), false)
    document.addEventListener('visibilitychange', this.onVisibilityChanged.bind(this), false)
    this.startSliderInterval()
  }
  render () {
    let {children, data, stepWidth, hoverStop, point, showItemNum, type} = this.props
    let {sliderIndex} = this.state
    let sliderData = children || data || []
    let showNum = showItemNum || 1
    let startData = sliderData.slice(0, showNum)
    let endData = sliderData.slice(sliderData.length - showNum, sliderData.length)
    let mapData = [...endData, ...sliderData, ...startData]
    return (
      <div className='slider-will'
           onMouseOver={() => { hoverStop && this.clearSliderInterval() }}
           onMouseOut={() => { this.startSliderInterval() }}>
        <div className='slider-cont'>
          <div className='turn-btn turn-left' onClick={() => { this.turnRightHandle() }} />
          <ul className={type === 'moveVertical' ? 'slider-ul-move-vertical' : 'slider-ul-move-horizontal'}
              ref={(sliderList) => (this.sliderList = sliderList)}
              style={{[type === 'moveVertical' ? 'top' : 'left']: `${-sliderIndex * (stepWidth || 1200)}px`}}
          >
            {
              children ? mapData : mapData.map((item, index) => {
                return (
                  <li key={`slider-${index}`}>
                    <a href={item.href} target='_blank'>
                      <img src={item.img} alt={item.alt} />
                    </a>
                  </li>
                )
              })
            }
          </ul>
          <div className='turn-btn turn-right' onClick={() => { this.turnLeftHandle() }} />
        </div>
        {point === false ? ''
          : <ul className='slider-point-box'>
            {
              sliderData.map((item, index) => {
                if (index % showItemNum === 0) {
                  return (
                    <li key={`slider-point-${index}`}
                        className={this.state.sliderIndex === (index / showItemNum + 1) ? 'select-point' : ''}
                        onClick={() => { this.setState({sliderIndex: index + 1}) }}
                    >
                      <a href='javascript:void(0);' />
                    </li>
                  )
                }
              })
            }
          </ul>
        }
      </div>
    )
  }
}
export default SliderMove

3.SliderOpacity.js 淡入淡出

import './slider.less'
class SliderOpacity extends React.Component {
  constructor (props) {
    super(props)
    this.sliderInterval = null
    this.state = {
      sliderIndex: 0,
      thisMoveOver: true// 本次轮播是否结束,未结束前,不可进行下次操作
    }
  }

  moveEnd () {
    this.setState({thisMoveOver: true})
  }
  // 向左
  turnLeftHandle () {
    let len = this.props.children || this.props.data
    this.setState((preState, props) => ({
      sliderIndex: preState.sliderIndex - 1 < 0 ? len.length - 1 : preState.sliderIndex - 1,
      thisMoveOver: false
    }))
  }
  // 向右
  turnRightHandle () {
    let len = this.props.children || this.props.data
    this.setState((preState, props) => ({
      sliderIndex: preState.sliderIndex + 1 > len.length - 1 ? 0 : preState.sliderIndex + 1,
      thisMoveOver: false
    }))
  }
  // 清除定时器
  clearSliderInterval () {
    clearInterval(this.sliderInterval)
  }
  // 重新开始定时器
  startSliderInterval () {
    let {autoRun, intervalTime} = this.props
    if (autoRun !== undefined && autoRun !== false) {
      this.clearSliderInterval()
      this.sliderInterval = setInterval(() => {
        switch (autoRun) {
          case 'left':
            this.turnLeftHandle()
            break
          case 'right':
            this.turnRightHandle()
            break
          default:
            return false
        }
      }, intervalTime)
    }
  }
  // 判断用户是否正在浏览当前页面
  onVisibilityChanged (e) {
    let hidden = e.target.hidden
    if (hidden) {
      clearInterval(this.sliderInterval)
    } else {
      this.startSliderInterval()
    }
  }
  componentDidMount () {
    document.addEventListener('visibilitychange', this.onVisibilityChanged.bind(this), false)
    this.startSliderInterval()
  }
  render () {
    let {children, data, stepWidth, hoverStop, point, showItemNum} = this.props
    let {sliderIndex} = this.state
    let mapData = children || data || []
    return (
      <div className='slider-will'
        onMouseOver={() => { hoverStop && this.clearSliderInterval() }}
        onMouseOut={() => { this.startSliderInterval() }}>
        <div className='slider-cont'>
          <div className='turn-btn turn-left' onClick={() => { this.turnLeftHandle() }} />
          <ul className='slider-ul-opacity'>
            {
              children ? mapData : mapData.map((item, index) => {
                return (
                  <li key={`slider-${index}`} className={sliderIndex === index ? 'selected-slider-item' : ''}>
                    <a href={item.href} target='_blank'>
                      <img src={item.img} alt={item.alt} />
                    </a>
                  </li>
                )
              })
            }
          </ul>
          <div className='turn-btn turn-right' onClick={() => { this.turnRightHandle() }} />
        </div>
        {point === false ? ''
          : <ul className='slider-point-box'>
            {
              mapData.map((item, index) => {
                return (
                  <li key={`slider-point-${index}`}
                    className={this.state.sliderIndex === index ? 'select-point' : ''}
                    onClick={() => { this.setState({sliderIndex: index}) }}
                  >
                    <a href='javascript:void(0);' />
                  </li>
                )
              })
            }
          </ul>
        }
      </div>
    )
  }
}
export default SliderOpacity

4.slider.less 样式文件

@import "../../../../plugin/less/class.less";
@imgSrc:'@{webpath_cn}activity/17-double11/';
.slider-will{
  width:100%;
  height:100%;
  position: relative;
  .slider-cont{
    width:100%;
    height:100%;
    position: relative;
    z-index: 0;
    overflow: hidden;
    &:hover{
      .turn-btn{
        display: block;
        z-index: 3;
      }
    }
  }
  .turn-btn{
    position: absolute;
    top:50%;
    .translate(0,-50%);
    width:47px;
    height: 67px;
    cursor: pointer;
    z-index: -1;
    display: none;
  }
  .turn-left{
    left:0;
    background:rgba(0,0,0,.5) url("@{imgSrc}turn_left.png") no-repeat center;
  }
  .turn-right{
    right:0;
    background:rgba(0,0,0,.5) url("@{imgSrc}turn_right.png") no-repeat center;
  }
  .slider-ul-move-horizontal{
    width: max-content;
    height:100%;
    position: absolute;
    left:0;
    top:0;
    .transition();
    &>li{
      display: table-cell;
    }
  }
  .slider-ul-move-vertical{
    width:100%;
    height:max-content;
    position: absolute;
    left:0;
    top:0;
    .transition();
    &>li{
      display: block;
    }
  }
  .slider-ul-opacity{
    width:100%;
    height:100%;
    position: relative;
    z-index: 1;
    &>li{
      position: absolute;
      left:0;
      top:0;
      opacity: 0;
      z-index: -1;
      .transition();
    }
    .selected-slider-item{
      opacity: 1;
      z-index: 2;
    }
  }
  .slider-point-box{
    border-radius: 10px;
    position: absolute;
    bottom: 15px;
    height: 13px;
    text-align: center;
    font-size: 0;
    left: 50%;
    .translate(-50%);
    background-color: rgba(255,255,255,.3);
    &>li{
      display: inline-block;
      margin: 3px;
      a{
        display: block;
        padding-top: 8px;
        width: 8px;
        height: 0;
        border-radius: 50%;
        background: #fff;
      }
    }
    .select-point{
      a{
        background: #ff5000;
      }
    }
  }
}
上一篇下一篇

猜你喜欢

热点阅读