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:站在巨人的肩膀上看世界会清晰)。 如果说方向,当今世人还不清晰准确。那么就大胆往前走吧,对与错并不重要。心中的方向更加重要。
  • 相关阅读:
    纯CSS实现小三角提示信息
    PostGIS+QGIS+GeoServer+OpenLayers实现数据的存储、服务的发布以及地图的显示
    Arcgis for Js之Graphiclayer扩展详解
    Arcgis for JS扩展GraphicLayer实现区域对象的聚类统计与展示
    Arcgis for JS之Cluster聚类分析的实现(基于区域范围的)
    Arcgis for JS之Cluster聚类分析的实现
    Arcgis for Js之featurelayer实现空间查询和属性查询
    RESTful WebService入门
    使用 Spring 3 来创建 RESTful Web Services(转)
    基于Spring设计并实现RESTful Web Services(转)
  • 原文地址:https://www.cnblogs.com/yuanjili666/p/13565308.html
Copyright © 2011-2022 走看看