zoukankan      html  css  js  c++  java
  • React 实现简易轮播图

      

     使用 ReactJS 实现一个简易的轮播图 (carousel) 组件。

    Task 1:在相框中展示图片,左右按钮切换当前图片

    实现思路;把图片横向排列成组(image row),放置在相框(frame)中,隐藏超出相框的部分。利用图片组左侧和相框左侧的距离(margin-left)改变当前展示在相框中的内容,点击左右按钮可以改变这个距离。

    // How to make use of this component
    
    <Carousel width={400} height={400}>
      {images.map(image => <img src={image} alt="" key={image}/>)}
    </Carousel>
    

      



    // Carousel component
    
    import React, { Component } from 'react';
    
    export default class Carousel extends Component {
      constructor(props) {
        super(props);
        this.state = { currentIndex: 0 };
        this.renderChildren = this.renderChildren.bind(this);
        this.setIndex = this.setIndex.bind(this);
      }
    
      renderChildren() {
        const { children, width, height } = this.props;
        const childStyle = {
           width,
          height: height
        };
    
        return React.Children.map(children, child => {
          const childClone = React.cloneElement(child, { style: childStyle });
          return (
            <div
              style={{
                display: 'inline-block'
              }}
            >
              {childClone}
            </div>
          );
        });
      }
    
      setIndex(index) {
        const len = this.props.children.length;
        const nextIndex = (index + len) % len;
    
        this.setState({ currentIndex: nextIndex });
      }
    
      render() {
        const { width, height } = this.props;
        const { currentIndex } = this.state;
    
        const offset = -currentIndex * width;
    
        const frameStyle = {
           width,
          height: height,
          whiteSpace: 'nowrap',
          overflow: 'hidden',
          position: 'relative'
        };
    
        const imageRowStyle = {
          marginLeft: offset,
          transition: '.2s'
        };
    
        const buttonStyle = {
          position: 'absolute',
          top: '40%',
          bottom: '40%',
           '10%',
          background: 'rgba(0,0,0,0.2)',
          outline: 'none',
          border: 'none'
        };
    
        const leftButtonStyle = {
          ...buttonStyle,
          left: 0
        };
    
        const rightButtonStyle = {
          ...buttonStyle,
          right: 0
        };
    
        return (
          <div className="carousel">
            <div className="frame" style={frameStyle}>
              <button
                onClick={() => this.setIndex(currentIndex - 1)}
                style={leftButtonStyle}
              >
                <
              </button>
              <div style={imageRowStyle}>{this.renderChildren()}</div>
              <button
                onClick={() => this.setIndex(currentIndex + 1)}
                style={rightButtonStyle}
              >
                >
              </button>
            </div>
          </div>
        );
      }
    }
    

      

    实现思路

    1. 如何显示block-level的div在同一行

      Solution 1:

      For parent element

    white space: nowrap
    

      For children elements

    display: inline block
    

      

    Solution 2:

    对同一行的div设置float属性

    float:left
    

      隐藏超出相框的图片部分

    overflow: hidden
    

      通过图片组和相框左侧的距离(margin-left)控制显示在相框中的内容,设置动画时间为0.2秒

    const offset = -(currentIndex * width)
    
    const imageRowStyle = {
      marginLeft: offset,
      transition: '.2s'
    };
    

      通过按钮来控制margin-left, 改变当前相框中内容

      setIndex(index) {
        const len = this.props.children.length;
        const nextIndex = (index + len) % len;
    
        this.setState({ currentIndex: nextIndex });
      }
      
      ...
      // in render function
      const {width, height} = this.props;
      const {currrentIndex} = this.state;
      const offset = - currentIndex * wid
      th
    

      放置按钮在相框中,设置合适大小,背景半透明,取消边框显示。

        const buttonStyle = {
          position: 'absolute',
          top: '40%',
          bottom: '40%',
           '10%',
          background: 'rgba(0,0,0,0.2)',
          outline: 'none',
          border: 'none'
        };
    
        const leftButtonStyle = {
          ...buttonStyle,
          left: 0
        };
    
        const rightButtonStyle = {
          ...buttonStyle,
          right: 0
        };
    

      

     

     
    实现思路市通过改变
     
    marginLeft,改变左侧间距,
    marginLeft的使用肯定市需要浮动定位和固定定位的结合,还有就是溢出隐藏,

    如果想这个过程中有动画效果,一个动火过度,就需要增加
    transition: '.2s'

      


     

    Task #2 平滑无限循环

    在之前的步骤中,我们使用了transiion来实现滑动动画。但当图片从最后一幅去到第一幅或者反之的时候,相框中会经过所有的图片,造成不连贯的体验。为了解决这个问题,我们可以在一头一尾多加上一副图片,当carousel处于最后一幅图片并点击next按钮的时候,首先把下一幅图片移动到相框,在动画结束的时候,再把相框中的图片切换为第一幅图片。

    这里需要使用requestAnimationFrame,来保证当动画结束的时候,立即改变component state。



    作者:一拾五
    链接:https://www.jianshu.com/p/07f36235eb2e
    来源:简书
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
     
     
     
    import React, { Component } from 'react';
    
    export default class Carouse extends Component {
      constructor(props) {
        super(props);
        this.state = { currentIndex: 1, offset: -this.props.width };
        this.renderChildren = this.renderChildren.bind(this);
        this.setIndex = this.setIndex.bind(this);
      }
    
      renderChildren() {
        const { children, width, height } = this.props;
        const childStyle = {
           width,
          height: height
        };
    
        if (!children) {
          return;
        }
    
        const appendedChildren = [
          children[children.length - 1],
          ...children,
          children[0]
        ];
    
        return React.Children.map(appendedChildren, (child, index) => {
          const childClone = React.cloneElement(child, { style: childStyle });
    
          return (
            <div
              style={{
                display: 'inline-block'
              }}
              key={index}
            >
              {childClone}
            </div>
          );
        });
      }
    
      setIndex(index) {
        let nextIndex = index;
        const len = this.props.children.length;
        const { width } = this.props;
    
        this.setState({ currentIndex: nextIndex });
    
        const currentOffset = this.state.offset;
        const nextOffset = -nextIndex * width;
    
        let start = null;
    
        const move = timestamp => {
          if (!start) {
            start = timestamp;
          }
    
          const progress = timestamp - start;
    
          this.setState({
            offset: currentOffset + (nextOffset - currentOffset) * progress / 100
          });
    
          if (progress < 100) {
            requestAnimationFrame(move);
          } else {
            if (nextIndex === 0) {
              nextIndex = len;
            } else if (nextIndex === len + 1) {
              nextIndex = 1;
            }
    
            this.setState({ currentIndex: nextIndex, offset: -nextIndex * width });
          }
        };
    
        requestAnimationFrame(move);
      }
    
      render() {
        const { width, height } = this.props;
        const { currentIndex, offset } = this.state;
    
        const frameStyle = {
           width,
          height: height,
          whiteSpace: 'nowrap',
          overflow: 'hidden',
          position: 'relative'
        };
    
        const imageRowStyle = {
          marginLeft: offset
        };
    
        const buttonStyle = {
          position: 'absolute',
          top: '40%',
          bottom: '40%',
           '10%',
          background: 'rgba(0,0,0,0.2)',
          outline: 'none',
          border: 'none'
        };
    
        const leftButtonStyle = {
          ...buttonStyle,
          left: 0
        };
    
        const rightButtonStyle = {
          ...buttonStyle,
          right: 0
        };
    
        return (
          <div className="carousel">
            <div className="frame" style={frameStyle}>
              <button
                onClick={() => this.setIndex(currentIndex - 1)}
                style={leftButtonStyle}
              >
                <
              </button>
              <div style={imageRowStyle}>{this.renderChildren()}</div>
              <button
                onClick={() => this.setIndex(currentIndex + 1)}
                style={rightButtonStyle}
              >
                >
              </button>
            </div>
          </div>
        );
      }
    }
    

      

     
     
     
     
    1、路在何方? 路在脚下 2、何去何从? 每个人都在探索,未来的方向在何处。如果说某些方向是世人已经公认的,那么就先按照公认的去走吧(ps:站在巨人的肩膀上看世界会清晰)。 如果说方向,当今世人还不清晰准确。那么就大胆往前走吧,对与错并不重要。心中的方向更加重要。
  • 相关阅读:
    Allegro PCB Design GXL (legacy) 使用slide无法将走线推挤到焊盘的原因
    OrCAD Capture CIS 16.6 导出BOM
    Altium Designer (17.0) 打印输出指定的层
    Allegro PCB Design GXL (legacy) 将指定的层导出为DXF
    Allegro PCB Design GXL (legacy) 设置十字大光标
    Allegro PCB Design GXL (legacy) 手动更改元器件引脚的网络
    magento产品导入时需要注意的事项
    magento url rewrite
    验证台湾同胞身份证信息
    IE8对css文件的限制
  • 原文地址:https://www.cnblogs.com/yuanjili666/p/13565308.html
Copyright © 2011-2022 走看看