React 輪播圖

1、框架搭建

  在該輪播圖中,將使用到三個組件:

  • ImgSlides // 輪播圖的頂層組件,用於狀態控制
  • ImgFigure // 圖片組件,用於接收頂層傳來的狀態,並顯示相應的圖片
  • ControllerUnit // 控制組件,用於控制圖片的顯示

首先,將這三個組件簡單實現,並編寫樣式:
ImgSlides 組件

import React, { Component } from 'react';
import '../style/component/imgSlides.css';
class ImgSlides extends Component {

  render() {
    return (
      <div className="slides">
        <ControllerUnit />
        <ImgFigure />
      </div>
    );
  }

}
export default ImgSlides;

ImgSlides 樣式

.slides{
  width: 100%;
  height: 40vw;
  position: relative;
  overflow: hidden;

}

ImgFigure 組件

import React, { Component } from 'react';
import '../style/component/imgFigure.css';
class ImgFigure extends Component {
  componentDidMount(){

  }
  render() {
    let arr = [];
    for(let i = 0; i < 3; i++){
      let imgContent =
      <img key={i.toString()} src=`${i.jpg}` alt=`${圖片i}`/>
      arr.push(imgContent);
    }
    return (
      <div className="imgs">{arr}</div>
    );
  }
}

export default ImgFigure;

ImgFigure 樣式

img{
  border: none;
  width: 100%;
  height: 40vw;
  transition: opacity 1s;
}
.imgs img{
  position: absolute;
  top: 0;
}

ControllerUnit 組件

import React, { Component } from 'react';
import '../style/component/controllerUnit.css';
class ControllerUnit extends Component {
  render() {
    let arr = [];
    for(let i = 0; i < 3; i++){
      let btnContent = 
          <span key={i.toString()} ></span>

        arr.push(btnContent);
    }
    return(
      <nav className="btns">{arr}</nav>
    );
  }
}
export default ControllerUnit;

ControllerUnit 樣式

.btns{
  display: flex;
  position: absolute;
  bottom: 1rem;
  z-index: 9;
  left: 50%;
  margin-left: -3rem;
}
.btns span{
  display: block;
  width: 1rem;
  height: 1rem;
  background: rgba(0, 0, 0, 0.5);
  border-radius: 50%;
  border: 2px solid rgba(0, 0, 0, 0.5);
  transition: background .5s;
  margin: 0.5rem;
}

2、圖片處理

  考慮到組件的靈活性,我們在組件中不將圖片信息寫死,而是從外部傳入,組件內部通過 props 獲得圖片信息。
  首先編寫圖片數據集:src/data/imageDatas.json

[
  {
    "filename":"home1.jpg",
    "title":"1",
    "desc":"it is 1.jpg"
  },
  {
    "filename":"home2.jpg",
    "title":"2",
    "desc":"it is 2.jpg"
  },
  {
    "filename":"home3.jpg",
    "title":"3",
    "desc":"it is 3.jpg"
  }
]

  接着,編寫圖片URL處理工具函數:src/util.js(其中圖片存放在src/images/x.jpg下)

export function getImageUrl(imageDatasArr){
  for(var i = 0; i < imageDatasArr.length; i++){
    var singleImageData = imageDatasArr[i];
    singleImageData.imageURL = require('./images/' + singleImageData.filename); 
    imageDatasArr[i] = singleImageData;
  }
  return imageDatasArr;
}

其中,通過 require 來請求圖片。
  最後在 App.js 中將圖片數據傳給 ImgSlides 組件。

import ImgSlides from './component/ImgSlides'
import {getImageUrl} from './util';
// 獲得圖片數據
var imageDatas = require('./data/imageDatas.json');
// 拼裝圖片URL
imageDatas = getImageUrl(imageDatas);

class App extends Component {
  render() {
    return <ImgSlides imageDatas={imageDatas}/>
  }
}

3、圖片輪播

  (1)圖片輪播中需要當前照片顯示狀態,即該那張圖片顯示,將該狀態定義在 ImgSlides 組件的 state 中,通過改變 state 來渲染組件。(ImgSlides 組件代碼片段)

class ImgSlides extends Component {
  constructor(props){
    super(props);
    this.state = {
      current: 0, // 當前圖片
      imgsArrangeArr: [ // 圖片樣式
        // { // 由於要是用動畫,所以不能使用 display: none
             // 注意樣式的值爲字符串
        //   visibility:'hidden', // 是否顯示,
        //   opacity: '0', // 透明度
        // }
      ]
  }
}

  (2)圖片狀態的改變,也放在 ImgSlides 組件中,這樣可以使 ImgFigure 組件只用來顯示,不進行圖片處理。(ImgSlides 組件代碼片段)

setImgArrange(current){
    let imgsArrangeArr = [];
    for (var i = 0; i < this.props.imageDatas.length; i++) {
      if(i === current){ // 如果是當前要顯示的圖片,
        imgsArrangeArr[i] = {
          visibility: 'visible',
          opacity: '100'
        }
      } else{
        imgsArrangeArr[i] = {visibility:'hidden', opacity: '0'}
      }
    }
    return imgsArrangeArr;
  }

  (3)設定定時器,來改變 this.state.current 的值。(ImgSlides 組件代碼片段)

setCurrent(){
    let _this = this;
    setInterval(function(){ 
       _this.setState(function(prev){
// 使用循環隊列的思想來設置 current 的值
         let current = (prev.current + 1) % this.props.imageDatas.length;
         let imgsArrangeArr = this.setImgArrange(current);
         return {current: current,
            imgsArrangeArr: imgsArrangeArr};
        });
    },5000);
  }

  (5)圖片數據、圖片狀態傳給 ImgFigure 組件(ImgSlides 組件代碼片段)

render() {
    return (
      <div className="slides" >
        <ControllerUnit />
        <ImgFigure data = {this.props.imageDatas} current={this.state.current} arrange={this.state.imgsArrangeArr}/>
      </div>
    );
  }

  (6)ImgFigure 組件中進行圖片顯示:(ImgFigure 組件代碼片段)

import React, { Component } from 'react';
import '../style/component/imgFigure.css';
class ImgFigure extends Component {

  render() {
    let arr = [];
    let img = this.props.data;
    for(let i = 0; i < img.length; i++){
      let imgContent =
      <img key={i.toString()} style={this.props.arrange[i]} src={img[i].imageURL} alt={img[i].desc}/>
      arr.push(imgContent);
    }
    return (
      <div className="imgs">{arr}</div>
    );
  }
}

export default ImgFigure;

4、控制按鈕實現

  控制按鈕實現的功能是:鼠標懸停在哪個按鈕上就顯示該按鈕對應的圖片。
  (1)由於圖片狀態是在 ImgSlides 組件中改變的,所以應該在 ImgSlides 組件中定義方法,在 ControllerUnit 組件中調用,來改變 ImgSlides 中圖片的狀態。(ImgSlides 組件代碼片段)

changeCurrent(index){ // index 表示,鼠標懸停在第 index 個按鈕上
    this.setState(function(prev){
      let imgsArrangeArr = this.setImgArrange(index); // 改變圖片顯示狀態
      return {current: index, // 改變狀態
      imgsArrangeArr: imgsArrangeArr}
    });
  }

  (2)將圖片信息,懸停改變圖片狀態方法傳給 ControllerUnit 組件。(ControllerUnit 組件代碼片段)

render() {

    return (
      <div className="slides" onMouseOver={this.hoverHandle} onMouseOut={this.hoverHandle}>
        <ControllerUnit current={this.state.current} changeCurrent={this.changeCurrent}  count={this.props.imageDatas.length} />
        <ImgFigure data = {this.props.imageDatas} current={this.state.current} arrange={this.state.imgsArrangeArr}/>
      </div>
    );
  }

  (3)在 ControllerUnit 組件中,實現鼠標懸停顯示圖片功能。由於在鼠標懸停事件發生時,要確定是鼠標懸停在哪個按鈕上,因此要將按鈕的 index 以參數的形式傳遞給方法。(ControllerUnit 組件代碼片段)

<span key={i.toString()} onMouseOver={this.changeCurrent(i)}></span>

由於事件綁定需要傳入的是函數,故 changeCurrent 函數應該返回一個閉包函數。(ControllerUnit 組件代碼片段)

changeCurrent(index){
    return function(){ 
// 在閉包函數中調用父組件的方法進行圖片狀態改變
      this.props.changeCurrent(index);
    }.bind(this);
  }

  (4) ControllerUnit 組件完整代碼

import React, { Component } from 'react';
import '../style/component/controllerUnit.css';
class ControllerUnit extends Component {
  constructor(props) {
    super(props);
    this.changeCurrent = this.changeCurrent.bind(this);
  }
  changeCurrent(index){
    return function(){
      this.props.changeCurrent(index);
    }.bind(this);
  }
  render() {
    let arr = [];
    for(let i = 0; i < this.props.count; i++){
      let btnContent = null;
      if(i === this.props.current){
        btnContent =
          <span key={i.toString()} style={{background: 'rgba(255,255,255,0.5)'}} onMouseOver={this.changeCurrent(i)}></span>
      } else{
        btnContent =
          <span key={i.toString()} onMouseOver={this.changeCurrent(i)}></span>
      }
        arr.push(btnContent);
    }
    return(
      <nav className="btns">{arr}</nav>
    );
  }
}
export default ControllerUnit;

5、鼠標懸停在圖片上停止輪播

  該功能可以看做是一個狀態的改變,當鼠標懸停在圖片上,關閉定時器,當鼠標移除,啓動定時器。但是,將定時器開啓關閉比較麻煩。我們需要的是將鼠標懸停在圖片上,輪播停止,只要我們不去更改 state.current 就可以將輪播停止。爲此,在 ImgSlides 定義狀態 (ImgSlides 組件代碼片段)

constructor(props){
    super(props);
    this.state = {
      current: 0, // 當前圖片
      isHover: false, // 鼠標是否懸停到組件上
      imgsArrangeArr: []
    }
}

  鼠標懸停事件處理(ImgSlides 組件代碼片段)
hoverHandle(){
this.setState(function(prev){
return {
isHover: !prev.isHover,
}
})
}
  事件綁定(ImgSlides 組件代碼片段)

render() {
    return (
      <div className="slides" onMouseOver={this.hoverHandle} onMouseOut={this.hoverHandle}>
        <ControllerUnit current={this.state.current} changeCurrent={this.changeCurrent}  count={this.props.imageDatas.length} />
        <ImgFigure data = {this.props.imageDatas} current={this.state.current} arrange={this.state.imgsArrangeArr}/>
      </div>
    );
  }

  停止更新 state.current 值(ImgSlides 組件代碼片段)

setCurrent(){
    let _this = this;
    setInterval(function(){
      if(!_this.state.isHover){
        // 當鼠標沒有懸停在組件上時,更新狀態
        _this.setState(function(prev){
          let current = (prev.current + 1) % this.props.imageDatas.length;
          let imgsArrangeArr = this.setImgArrange(current);
          return {current: current,
            imgsArrangeArr: imgsArrangeArr};
        });
      } else{
        return null;
      }
    },5000);
  }

6、完整代碼:https://github.com/lujinming1/react-slides

7、Demo:https://lujinming1.github.io/react-slides/

發佈了68 篇原創文章 · 獲贊 20 · 訪問量 14萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章