如何做到可扩展的组件。

来源:6-8 扩展作业 - 轮播图组件设计

慕斯6088333

2019-06-12

老师,您好,
我完成了轮播图的组件。本来是想要children来实现更加可扩展性的轮播图组件。但是我碰到了一些问题。比如说子组件要调用父组件的方法以及state(比如item.index是否与state中currentItemIndex相同。但是在React.children.map中,我去访问这些组件内容。我尝试了用了挺多种方法。 但是结果都是一些东西undefine啊什么的。。 比如这里的方法 https://codepen.io/Yuschick/post/react-passing-state-to-props-children-in-jsx。我看完了试了一下,并不是特别好用。

不知道老师是否能够提供一些 方式去解决它呢。

另外一点就是访问本地资源的问题。。 比如我现在的程序只是去访问src 底下的 img文件夹中的文件。倘若我们去访问其它路径的文件夹,该如何解析呢。。我尝试着把文件放到其它地方。 然后用require()去获取,得到Error:Cannot find module。。。。(比如以后可能增加用户模块上传自定义轮播图之类的。如果是用springboot搭建,可能存在target文件下)

还有就是像轮播图按钮这种的大小。最好能做成responsive design 。 不过在react.js中去改变css的样式。我感觉还挺麻烦的。

Carousels component (没写太多注释,还请见谅)

import React from 'react';
import {MOVE_PRE, MOVE_NEXT} from '../utilities/PriceUtility'

/**
 * props: height, width,totalImages 
 * isAutoChange: true,intervalTime: 2000,
 * onMouseEnter onMouseLeave
 */
export class Carousels extends React.Component{

    constructor(props){
        super(props)
        this.state = {
            currentImgIndex: 0,
            intervalTime: 3000,
            isAutoChange: true,
        }
    }

    

    /**
     * Will Call after construction if we allow auto-changable Carousels
     * Set interval change state every 2 second.
     */
    componentDidMount() {
        if (this.props.isAutoChange){
            this.timer = setInterval(this.changeAutoDisplayImgIndex, this.state.intervalTime)
        }
    }

    /**
     * Auto change items by the timer
     */
    changeAutoDisplayImgIndex = ()=>{
        let imgIdx = this.state.currentImgIndex
        let totalItems = this.props.totalItems
        this.setState({
            currentImgIndex: imgIdx === totalItems - 1 ? 0 : imgIdx + 1
        })
    }
    
    /**
     * change items by clicking left/right button 
     */
    handleButtonChange = (event,moveType) =>{
        event.preventDefault()
        //stop timer
        clearInterval(this.timer)
        let imgIdx = this.state.currentImgIndex
        let totalItems = this.props.totalItems
        if (moveType === MOVE_PRE){
            this.setState({
                currentImgIndex: imgIdx === 0 ? totalItems - 1: imgIdx - 1,
            })
        } else if (moveType === MOVE_NEXT){
            this.setState({
                currentImgIndex: imgIdx === totalItems - 1 ? 0 : imgIdx + 1,
            })
        }
        // restart timer 
        this.timer = setInterval(this.changeAutoDisplayImgIndex, this.state.intervalTime)
    }

    /**
     * change items by clicking points underware
     */
    handlePointsChange = (event,index) => {
        event.preventDefault()
        //stop timer
        clearInterval(this.timer)
        this.setState({
            currentImgIndex: index,
        })
        // restart timer 
        this.timer = setInterval(this.changeAutoDisplayImgIndex, this.state.intervalTime)
    }

    
    
    /**
     * Mouse Enter: stop timer 
     */
    handleMouseEnter = (event) =>{
        event.preventDefault()
        //stop timer
        clearInterval(this.timer)
    }
    /**
     * Mouse Enter: start timer
     */
    handleMouseLeave = (event) => {
        event.preventDefault()
        // restart timer 
        this.timer = setInterval(this.changeAutoDisplayImgIndex, this.state.intervalTime)
    }
    
    componentWillUnmount(){
        //stop timer
        clearInterval(this.timer)
    }

    render(){

        const { height, width, items} = this.props
        const { currentImgIndex} = this.state
        const displayItem = items[currentImgIndex]
        console.log(displayItem)
        /**
         * CSS styles
         */
        const frameStyle = {
            width: width,
            height: height,
            whiteSpace: 'nowrap',
            overflow: 'hidden',
            position: 'relative',
            margin: '100px auto'
        };

        const imageRowStyle = {
            width: '100%',
            height: '100%',
        };

        const buttonStyle = {
            position: 'absolute',
            top: '40%',
            bottom: '40%',
            width: '10%',
            background: 'rgba(0,0,0,0.5)',
            outline: 'none',
            color: '#fff',
            border: 'none',
            fontSize: '50px'
        };

        const leftButtonStyle = {
            ...buttonStyle,
            left: '0'
        }

        const rightButtonStyle = {
            ...buttonStyle,
            right: '0'
        }

        const pointsStyle = {
            position: 'absolute',
            left: '50%',
            bottom: '10%'
        }

        return(
            <div className = "carousel-component" style={frameStyle}>
                <button onClick={(event) => this.handleButtonChange(event, MOVE_PRE)} style={leftButtonStyle}>
                    &lt;
                        </button>
                <img className='carousel-component-child' style={imageRowStyle}
                        onMouseEnter={(event) => this.handleMouseEnter(event)}
                        onMouseLeave={(event) => this.handleMouseLeave(event)}
                        src={displayItem.address} alt="#">
                </img>                   
                <button onClick={(event) => this.handleButtonChange(event, MOVE_NEXT)} style={rightButtonStyle}>
                    &gt;
                </button>
                <div className ="pointsTab" style = {pointsStyle}>
                    {this.props.items.map((item,index) => {
                        const pointStyle = {
                            display: "inline-block",
                            width: "15px",
                            height: "15px",
                            margin: "15px",
                            borderRadius: "50%",
                        }
                        const generatePointColor = (index)=>{
                            return index === this.state.currentImgIndex ?
                                { ...pointStyle, background: '#3333FF'} : { ...pointStyle,background: '#fff'}
                        }
                        return(
                            <button key = {index} style={generatePointColor(index)}
                                onClick={(event) => { this.handlePointsChange(event, index)}}></button>
                        )
                    })}
                </div>
            </div>
        )
                
    }

}

/**
 * 注释掉的失败方法 
 * 
 
export const Carousel = ({ children }) => {
    return <React.Fragment>{children}</React.Fragment>
}
*/

/**
  失败的方法:       
const childWithProp = React.Children.map(children, (child) => {
    return React.cloneElement(child,
        {
            handleButtonChange: this.handleButtonChange,
            handleMouseEnter: this.handleMouseEnter,
            handleMouseLeave: this.handleMouseLeave,
            currentImgIndex: currentImgIndex,
            handlePointsChange: this.handlePointsChange,
        });
});
* props that child component needed
*/

常量相关

export const images = [
    {
        'address': require('../img/user_03_carousel_01.jpg'),
    },

    {
        'address': require('../img/user_03_carousel_02.jpg'),
    },

    {
        'address': require('../img/user_03_carousel_03.jpg'),
    }
]

export const MOVE_PRE = 'pre';
export const MOVE_NEXT = 'next';

调用

 <Carousels height={720} width={'100%'} totalItems={images.length} items= {images}></Carousels>`

图片描述

写回答

1回答

张轩

2019-06-12

谢谢你认真做作业的态度,问题较多,我会在周末比较空闲的时候写。?

1
1
慕斯6088333
谢谢,非常感谢。我最近有空也优化一下自己写的第六章的代码。顺便写个轮播图的测试代码。。
2019-06-13
共1条回复

React16组件化+测试+全流程 实战在线账本项目

轻松上手,从设计图到上线,精通组件化思维和组件测试

713 学习 · 177 问题

查看课程