好的,基本上我正在尝试从头开始为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);
}