React 輪播圖實現

接到項目, 用react和material-ui實現輪播圖. 搜索了一些方法參考, 不論語言/框架的使用,大致上分爲兩種思路react

超寬列表實現法

在原生JS或者JQuery中,輪播圖的實現通常是這樣子的數組

設置一個ul, 把全部圖片橫向展開,複製第一張圖到最後,設置顯示的界面 正好爲一張圖的大小和寬度,而後不斷向後移動. 到最後一張圖時無變化的切換到第一張, 數據結構

橙色框爲顯示穿體,能夠想象成在後面抽動圖片條, 抽到後一個的時候瞬間無動畫的回到初始狀態.框架

這個能夠類比數據結構中的循環數組,首尾相連,從一個元素開始能夠遍歷完整個隊列而後回到初始元素,相似項鍊的一個圈.ide

 

循環隊列顯示法

而咱們觀察到,影響整個動畫的只有3個元素,當前圖像和先後兩個圖像,所以能夠類比數據結構中的循環隊列,每次只記錄當前元素和當前元素先後的狀態,用index指向當前元素便可動畫

 

那麼就有三種狀態ui

center 顯示在屏幕中間的圖片this

left 即將從屏幕中移除的圖片,動畫效果直到徹底出屏幕spa

right 即將進入屏幕的圖片,動畫效果從右側貼緊屏幕到正中3d

 

圖片被包裹在一個div中 如下爲代碼

 

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { withStyles } from '@material-ui/core/styles';

const styles = ({
  root: {
    position: "relative",
    padding: 0,
    margin: 0,
    overflow: "hidden",
    width: "100%",
  },
  center: {
    position: "relative",  //顯示在中間的要撐開div
    width: "100%",
    left: 0,  //用於transition動畫,必須設定left值
    transition :"all 1s ease-in-out",
  },
  right: {
    position :"absolute",
    left: "100%",
    width: "100%",
    top: 0,
  },
  left: {
    position :"absolute",
    left: "-100%",
    width: "100%",
    top: 0,
    transition :"all 1s ease-in-out",
  }
});

class Slideshow extends Component {

  state = {
    index: 0,
    images: [],
  };

  turn = step => {
    let index = this.state.index + step;
    if (index >= this.state.images.length) {
      index = 0;
    }
    if (index < 0) {
      index = this.props.images.length - 1;
    }
    this.setState({ index: index })
  };

  go = () => {
    this.timer = setInterval(
      () => this.turn(1),
      this.props.delay * 1000,
    )
  };

  clear = () => {
    clearInterval(this.timer)
  };

  componentDidMount() {
    const images = [
       require('../image/1.jpg'),
       require('../image/2.jpg'),
       require('../image/3.png'),
    ];
    this.setState({
      images: images,
    });
    this.go()
  };


  componentWillUnmount() {
    this.clear();
  }

  render() {
    const { classes } = this.props;

    return (
      <div
        className={classes.root}
        onMouseOver={this.clear}  //鼠標懸停時中止計時
        onMouseLeave={this.go}
      >
        { this.state.images.map((item, index) => (
          <img
            src={ item }
            alt=""
            key={index}
            className={ classNames(
            { [classes.center]: index === this.state.index },
            {
              [classes.right]:
              index === this.state.index + 1 || (index === 0 && this.state.index === this.state.images.length - 1)
            },
            {
              [classes.left]:
              index === this.state.index - 1 || (index === this.state.images.length - 1 && this.state.index === 0)
            },
          ) }/>
        ))
        }
      </div>
    )

  }
}


Slideshow.propTypes = {
  classes: PropTypes.object.isRequired,
};

export default withStyles(styles)(Slideshow);

 

有了基本框架以後,向左向右翻動的按鈕和顯示頁數的按鈕也能夠直接作出來了. 只須要改變當前頁面的index便可生效

 

在作按鈕的時候發現一個問題,這個方法在只有3張圖片的時候 會有奇怪的狀況出現.緣由是由於 只有3張圖片 每一張都是本體 前驅 後繼 每次轉換的時候都會進行一次transform

解決辦法 用4張圖片 或者設置left和right 的opacity:0

相關文章
相關標籤/搜索