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);
}