从头开始的ReactJS响应式旋转木马

时间:2017-04-27 21:02:39

标签: node.js reactjs ecmascript-6 jsx

好的,基本上我正在尝试从头开始为ReactJS写一个旋转木马。
我已经完成了代码必须具有导航,幻灯片等所需的功能。

这样做的主要目的是让它具有响应性,但这就是我很难搞清楚如何做。

carousel.js

import React from 'react'
import { NavLink } from 'react-router-dom'
import classNames from 'classnames'

export default class Carousel extends React.Component {

    constructor(props) {
      super(props)

      this.handleNext = this.handleNext.bind(this)
      this.handlePrev = this.handlePrev.bind(this)

      this.state = {
        innerWidth: 0,
        navPrevDisabled: true
      }
    }

    componentWillMount() {
      var stateItems = []

      for(let i in this.props.items) {
        stateItems.push(
          <div className="react-item movie" key={i}>
            <div className="front">
              <div className="front-image" style={{backgroundImage: `url(${this.props.items[i].poster})`}}>
              </div>
              <div className="backdrop medium">
                <div className="react-play-button fill">
                  <figure className="icon-content"></figure>
                </div>
              </div>
            </div>
          </div>
        )
      }

      this.setState({
        items: stateItems
      })
    }

    componentWillUnmount() {
      window.removeEventListener("resize", this.updateCarousel, false)
    }

    updateCarousel = () => {
      var $reactItem = $('.carousel-wrapper .carousel-inner .react-item')
      var maxw = $('.carousel-wrapper').width()

      /*var slideItemsFit = $reactItem.filter(function () {
        return $(this).position().left < maxw
      }).length*/

      var itemsFitSlide = Math.floor(maxw / $reactItem.outerWidth(true))

      console.log(itemsFitSlide)

      var margin = $reactItem.outerWidth(true) * itemsFitSlide

      margin = (maxw - margin) / itemsFitSlide / 2

      $reactItem.css({marginLeft: `${margin}px`, marginRight: `${margin}px`})

      this.setState({
        itemsShownTotal: itemsFitSlide,
        itemWidth: $reactItem.outerWidth(true),
        navNextDisabled: (itemsFitSlide === this.state.items.length),
        itemsFitSlide: itemsFitSlide
      })
    }

    componentDidMount() {
      this.updateCarousel()
      window.addEventListener("resize", this.updateCarousel, false)
    }

    handleNext(e) {
      var state = this.state
      var maxw = $('.carousel-wrapper').width()

      var innerWidth = -Math.abs(state.innerWidth - (state.itemWidth * state.itemsFitSlide))

      var itemsLeft = state.items.length - state.itemsShownTotal
      var lastSlide = state.itemsFitSlide > itemsLeft

      if(lastSlide) {
        innerWidth = -Math.abs(state.innerWidth - (state.itemWidth * itemsLeft))
      }

      var itemsShownTotal = (lastSlide)
        ? state.itemsShownTotal + itemsLeft
        : state.itemsShownTotal + state.itemsFitSlide

      this.setState({
        itemsShownTotal: itemsShownTotal,
        innerWidth: innerWidth,
        navPrevDisabled: false,
        navNextDisabled: itemsShownTotal === state.items.length
      })
    }

    handlePrev(e) {
      var state = this.state

      var innerWidth = state.innerWidth + (state.itemWidth * state.itemsFitSlide)

      //var itemsLeft = state.itemsFitSlide - state.itemsShownTotal

      var firstSlide = false
      if(innerWidth >= 0) {
        firstSlide = true
        innerWidth = 0
      }

      var itemsShownTotal = (firstSlide)
        ? state.itemsFitSlide
        : state.itemsShownTotal - state.itemsFitSlide

      this.setState({
        itemsShownTotal: itemsShownTotal,
        innerWidth: innerWidth,
        navPrevDisabled: firstSlide,
        navNextDisabled: false
      })
    }

    render() {
      var nav = {
        prev: classNames({
          navigation: true,
          prev: true,
          disabled: this.state.navPrevDisabled,
          whiteframe: true
        }),
        next: classNames({
          navigation: true,
          next: true,
          disabled: this.state.navNextDisabled,
          whiteframe: true
        })
      }
      return (
        <section className="block collection carousel portrait">
          <div className="scaffold">
            <i className={nav.prev} onClick={this.handlePrev}></i>
            <i className={nav.next} onClick={this.handleNext}></i>
            <header className="collection-header">
              <NavLink to={this.props.route}>
                <h2>{this.props.title}</h2>
              </NavLink>
            </header>
            <div className="carousel-wrapper">
              <div className="carousel-inner use-transition" style={{transform: `translateX(${this.state.innerWidth}px)`}}>
                {this.state.items}
              </div>
            </div>
          </div>
        </section>
      )
    }

}

基本上让我们说幻灯片中有5张图片,但是在封面中只有足够的宽度来容纳4张图片,然后我想重做这个过程并将4幅图像边缘化以适应包装器的中心。

carousel.css

.scaffold {
  position: relative;
}

.block.collection .collection-header {
    margin: 0 0 20px;
    position: relative;
    padding-top: 20px;
}
  .block.collection .collection-header h2 {
    outline: none;
    text-decoration: none;
    margin: 0;
    color: #212d33;
    font-size: 2.6rem;
    letter-spacing: -0.01em;
    line-height: 36px;
    font-weight: normal;
  }
.block.collection.carousel .carousel-wrapper {
  overflow: hidden;
  width: 100%;
}
.block.collection.carousel .carousel-wrapper .carousel-inner {
    display: inline-block;
    margin-right: 5px;
    white-space: nowrap;
}
  .block.collection.carousel .carousel-wrapper .carousel-inner.use-transition {
      transition: transform 0.5s ease-out;
  }

  .block.collection.portrait .react-item {
      width: 186px;
      margin: 0 0px 20px 0px;
  }
  .block.collection.portrait .react-item.hidden {
    opacity: 0;
  }

  .block.collection .react-item {
      position: relative;
      display: inline-block;
      vertical-align: top;
      margin-top: 10px;
      margin-bottom: 10px;
  }

  .block.collection.portrait .react-item .front {
    height: 279px;
}

.block.collection .react-item .front {
    background-color: #212d33;
    position: relative;
    display: block;
    text-decoration: none;
}

.block.collection .react-item .front .front-image {
    animation: fadein 500ms;
    position: absolute;
    height: 100%;
    width: 100%;
    top: 0;
    left: 0;
    background-size: cover;
}

.block.collection .react-item .backdrop {
  transition: opacity 0.1s ease-in-out;
opacity: 0;
height: 100%;
position: absolute;
width: 100%;
top: 0;
left: 0;
z-index: 5;
text-align: center;
background: rgba(15, 22, 26, 0.25);
}
.block.collection .react-item .backdrop:hover {
  opacity: 1;
}

.react-play-button.fill {
    margin: 0;
    width: 100%;
    height: 100%;
    background-size: 68px;
}

.react-play-button {
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: transparent;
    border: 0;
    padding: 0;
    cursor: pointer;
}

.react-play-button .icon-content {
    width: 68px;
    height: 68px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyBoZWlnaHQ9IjEwMCUiIHdpZHRoPSIxMDAlIiB2aWV3Qm94PSIwIDAgMTAwIDEwMCIgdmVyc2lvbj0iMS4wIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIj4KICAgIDxzdHlsZT48IVtDREFUQVsKICAgICAgICBnIHsKICAgICAgICAgICAgc3Ryb2tlOiAjZmZmOwogICAgICAgIH0KICAgICAgICBnIGNpcmNsZSB7CiAgICAgICAgICAgIGZpbGw6IHJnYmEoMCwwLDAsMC4wKTsKICAgICAgICAgICAgc3Ryb2tlLXdpZHRoOiA0OwogICAgICAgIH0KICAgICAgICBnIHBvbHlsaW5lIHsKICAgICAgICAgICAgZmlsbDogdHJhbnNwYXJlbnQ7CiAgICAgICAgICAgIHN0cm9rZS13aWR0aDogMTA7CiAgICAgICAgfQogICAgXV0+PC9zdHlsZT4KCiAgICA8Zz4KICAgICAgICA8Y2lyY2xlIHI9IjQ4IiBjeD0iNTAiIGN5PSI1MCIgLz4KICAgICAgICA8cG9seWxpbmUgcG9pbnRzPSI0MSwyOCA2Myw1MCA0MSw3MiIgLz4KICAgIDwvZz4KPC9zdmc+);
    background-size: contain;
    background-position: center;
    background-repeat: no-repeat;
}

.block.collection.carousel .navigation {
  top: 49%;
  border: none;
  cursor: pointer;
  position: absolute;
  width: 66px;
  background: rgba(249, 249, 251, 0.7);
  width: 48px;
  height: 60px;
  display: block;
  font-size: 0;
  border-radius: 2px;
  z-index: 10;
  opacity: 1;
  pointer-events: auto;
  transition: opacity .3s ease-in-out;
}
.block.collection.carousel .navigation.disabled {
  opacity: 0;
  pointer-events: none;
}
.block.collection.carousel .navigation:hover {
  background-color: #FFF;
}
.block.collection.carousel .navigation:hover::after {
  opacity: 1;
}
.block.collection.carousel .navigation.prev {
  left: -25px;
}
.block.collection.carousel .navigation.next {
  right: -25px;
}

.block.collection.carousel .navigation::after {
  transition: opacity .5s ease;
    background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDE5LjIuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPgo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IgoJIHZpZXdCb3g9IjAgMCAxMy40IDI0IiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCAxMy40IDI0OyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+CjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+Cgkuc3Qwe2ZpbGw6IzIxMkQzMzt9Cjwvc3R5bGU+CjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik0wLDEuNEwxMC42LDEyTDAsMjIuNkwxLjQsMjRsMTItMTJMMS40LDBMMCwxLjR6Ii8+Cjwvc3ZnPgo=) no-repeat;
    width: 16px;
    height: 24px;
    content: '';
    position: absolute;
    top: 18px;
    left: 18px;
    opacity: 0.7;
}
.block.collection.carousel .navigation.prev::after {
  left: 13px;
  transform: rotate(180deg);
}

0 个答案:

没有答案