专栏首页菜鸟计划写一个简单的轮播组件

写一个简单的轮播组件

直接上代码

App.js文件

let list = [
    {
        id: 1,
        img: require('./static/image/one.jpg')
    },
    {
        id: 2,
        img: require('./static/image/two.jpg')
    },
    {
        id: 3,
        img: require('./static/image/three.jpg')
    }
];
render() {
    return (
        <div>
            <Banner list={list}></Banner>
        </div>
    );
}

banner.js文件
import React from 'react';
import PropTypes from 'prop-types';
import {Button} from 'antd'
import '../static/css/banner.scss'

export default class Banner extends React.Component{
    //设置默认值
    static defaultProps = {
        list: [],
        interval: 3000,
    }
    //设置默认规则
    static propTypes = {
        list: PropTypes.array,
        interval: PropTypes.number
    }
    //初始化状态值
    constructor(){
        super();
        this.state = {
            step: 1,
            speed: '0.2s'
        }
    }
    //组件挂载前进行数据预处理
    componentWillMount() {
        this.list = [this.props.list[this.props.list.length - 1], ...this.props.list, this.props.list[0]];
    }
    //组件挂载完成触发事件
    componentDidMount() {
        this.autoMove();
    }
    //组件更新前进行判断处理
    componentWillUpdate(nextProps, nextState, nextContext) {
        if (nextState.step >= this.list.length) {
            this.setState({
                step: 1,
                speed: '0s'
            });
        }
        if (nextState.step === -1) {
            this.setState({
                step: this.list.length - 2,
                speed: '0s'
            });
        }
    }
    //组件完成更新进行判断处理
    componentDidUpdate(prevProps, prevState, snapshot) {
        if(this.state.step === 1 && this.state.speed === '0s'){
            //js设置transition,不能在主栈队列执行时候遇到多次,这样渲染以最后一次为主,此时我们可以把第二次操作移动到EventQueue中。
            let delayTimer = setTimeout(()=> {
                this.setState({
                    step: this.state.step+1,
                    speed: '0.2s'
                });
            }, 50);
        }
        if (this.state.step === 3 && this.state.speed === '0s') {
            let delayTimer = setTimeout(()=> {
                this.setState({
                    step: this.state.step - 1,
                    speed: '0.2s'
                });
            }, 50);
        }
    }
    autoMove = ()=> {
        this.autoTime = setInterval(()=> {
            this.setState({
                step: this.state.step+1
            })
        }, this.props.interval)
    }
    handleClick = (e)=> {
        if (e.target.tagName === 'BUTTON') {
            let dir = e.target.getAttribute('dir');
            this.setState({
                step: dir === 'LEFT' ? this.state.step - 1 : this.state.step+1,
                speed: '0.2s'
            })
        }
    };
    render() {
        let wrapperStyle = {
          width: `${this.list.length*1000}px`,
          left: `${-this.state.step*1000}px`,
          transition: `left ${this.state.speed} linear 0s`
        };
        return (
            //利用事件委托统一处理
            <div className={'banner_container'} onMouseEnter={event => {clearInterval(this.autoTime)}} onMouseLeave={this.autoMove} onClick={this.handleClick}>
                <div className={'wrapper'} style={wrapperStyle}>
                    {
                        this.list.map((item,index) => {
                            let {img} = item;
                            return (
                                <div className={'slide'} key={index}>
                                    <img src={img}/>
                                </div>
                            )
                        })
                    }
                </div>
                <Button dir={'LEFT'}>左</Button>
                <Button dir={'Right'}>右</Button>
            </div>
        )
    }
}
banner.scss文件
.banner_container{
  margin: 20px auto;
  width: 1000px;
  height: 300px;
  overflow: hidden;
  position: relative;
  .wrapper{
    position: absolute;
    left: 0;
    top: 0;
    width: 3000px;
    height: 300px;
    .slide{
      font-size: 14px;
      width: 1000px;
      height: 300px;
      line-height: 300px;
      text-align: center;
      float: left;
      img{
        background:no-repeat center;
        width: 100%;
        height: 100%;
      }
    }
  }
  button:nth-child(2){
    position: absolute;
    left: 0;
    bottom: 0;
  }
  button:nth-child(3){
    position: absolute;
    right: 0;
    bottom: 0;
  }
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • react入门(三):state、ref & dom简解

    作用:组件内部的状态重新更新时,可以控制组件内部重新渲染(不需要重新调取组件也可以重新渲染)

    柴小智
  • vue计算属性详解——小白速会

    一、什么是计算属性 模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护。例如: <div id="exam...

    柴小智
  • react入门(六):状态提升&context上下文小白速懂

    使用 react 经常会遇到几个组件需要共用状态数据的情况。这种情况下,我们最好将这部分共享的状态提升至他们最近的父组件当中进行管理。

    柴小智
  • react中常规删除功能

    // let message = ( <div><p > 商机删除后列表将不可见此商机, 请谨慎操作! </p> </div>);

    botkenni
  • Vue 绑定简单分析实现

    使用js es6 中 Object.defineProperty为我们自己定义的VM创建示例。同时这个方法通过提供了set.get方法的触发我们的监听事件。

    deep_sadness
  • 《你不知道的JavaScript》:js委托设计的真实案例与总结

    实际需求,web开发中有一个典型的前端场景,创建UI控件(按钮、下拉列表等)。用jq的选择器来简化选择过程,与实现思路不冲突。

    前端_AWhile
  • jQuery开发技巧

    版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。

    奋飛
  • 封装移动端 vue 拖拽指令

    copy_left
  • 计数器、滑动窗口、漏桶、令牌算法比较和伪代码实现

    计数器是限流里最简单的,简单来说,比如 我限制1分钟内 请求数最多为60个! 当此刻 2018-02-27 16:23:00 到 2018-02-27 16:2...

    用户2825413
  • 面试题:你能写一个Vue的双向数据绑定吗?

    Vue的双向数据绑定的原理相信大家也都十分了解了,主要是通过 Object对象的defineProperty属性,重写data的set和get函数来实现的,这里...

    :::::::

扫码关注云+社区

领取腾讯云代金券