Skip to content

Instantly share code, notes, and snippets.

@johndavedecano
Created February 27, 2019 09:00
Show Gist options
  • Save johndavedecano/334b794fb2997f8eaedd9f2a05f08c4f to your computer and use it in GitHub Desktop.
Save johndavedecano/334b794fb2997f8eaedd9f2a05f08c4f to your computer and use it in GitHub Desktop.
Slider
import React, { Component } from 'react';
import { render } from 'react-dom';
import Slider from './Slider'
import SliderItem from './SliderItem'
import './style.css';
class App extends Component {
constructor() {
super();
this.state = {
name: 'React'
};
}
handleChangeSlide = index => {
console.log(index)
}
render() {
return (
<div className="Slider__Wrapper">
<Slider onChangeSlide={this.handleChangeSlide}>
<SliderItem>
<img src="https://placeimg.com/1000/500/animals" />
</SliderItem>
<SliderItem>
<img src="https://placeimg.com/1000/500/arch" />
</SliderItem>
<SliderItem>
<img src="https://placeimg.com/1000/500/nature" />
</SliderItem>
<SliderItem>
<img src="https://placeimg.com/1000/500/people" />
</SliderItem>
</Slider>
</div>
);
}
}
render(<App />, document.getElementById('root'));
import React from 'react'
import debounce from 'lodash/debounce'
import PT from 'prop-types'
class Slider extends React.Component {
static defaultProps = {
timeout: 3000,
autoPlay: true,
transition: 'ease',
transitionDelay: '.5s',
onChangeSlide: () => { },
}
static propTypes = {
timeout: PT.number,
autoPlay: PT.bool,
transition: PT.oneOf([
'ease',
'linear',
'ease-in',
'ease-out',
'ease-in-out'
]),
transitionDelay: PT.string,
onChangeSlide: PT.func,
}
state = {
currentIndex: 0,
width: 0,
isResizing: false
}
sliderRef = React.createRef()
contentRef = React.createRef()
tick = null
resizeTick = null
resizeTimeout = 500
constructor(props) {
super(props)
this.handleWindowResize = debounce(this.handleWindowResize)
}
componentDidMount() {
this.calculateContentWidth()
this.calculateSliderWidth()
window.addEventListener("resize", this.handleWindowResize)
this.setupTransition()
}
componentWillUnmount() {
window.removeEventListener("resize", this.handleWindowResize)
this.clearTimers()
}
getParentWidth() {
return this.sliderRef.current.parentElement.clientWidth
}
calculateSliderWidth() {
const width = this.getParentWidth()
this.sliderRef.current.style.maxWidth = `${width}px`
this.sliderRef.current.querySelectorAll('.Slider__Item').forEach(el => {
el.style.width = `${width}px !important`
})
}
calculateContentWidth() {
const width = this.sliderRef.current.offsetWidth * this.props.children.length
this.contentRef.current.style.width = `${width}px`
}
handleWindowResize = () => {
this.clearTimers()
this.resizeTick = setTimeout(this.doneResizing, this.resizeTimeout)
}
doneResizing = () => {
this.clearTimers()
this.calculateContentWidth()
this.calculateSliderWidth()
this.setupTransition()
}
setupTransition = () => {
if (this.props.autoPlay) {
this.tick = setInterval(this.handleTransition, this.props.timeout)
}
}
clearTimers = () => {
clearTimeout(this.resizeTimeout)
clearInterval(this.tick)
}
slideToIndex = (currentIndex) => {
const { transitionDelay, transition, onChangeSlide } = this.props
onChangeSlide({
prevIndex: this.state.currentIndex,
newIndex: currentIndex,
})
this.setState({
currentIndex,
}, () => {
if (currentIndex === 0) {
this.contentRef.current.style.transition = `.10s ${this.props.transition}`
this.contentRef.current.style.transform = 'translate(0%)'
} else {
const parentWidth = this.getParentWidth()
const fullWidth = parentWidth * this.props.children.length
const indexWidth = parentWidth * currentIndex
const percentageValue = indexWidth / fullWidth * 100
this.contentRef.current.style.transform = `translate(-${percentageValue}%)`
this.contentRef.current.style.transition = `${transitionDelay} ${transition}`
}
})
}
handleTransition = () => {
this.slideToIndex(this.getIndexSlideIndex())
}
getIndexSlideIndex = () => {
const lastIndex = this.props.children.length - 1
if (this.state.currentIndex === lastIndex) {
return 0
} else {
return this.state.currentIndex + 1
}
}
render() {
const { children } = this.props
return (
<div ref={this.sliderRef} className="Slider">
<div ref={this.contentRef} className="Slider__Content">
{children}
</div>
</div>
)
}
}
export default Slider
import React from 'react'
import PT from 'prop-types'
class SliderItem extends React.Component {
static defaultProps = {
width: ''
}
static propTypes = {
width: PT.string,
}
render() {
const { children, width } = this.props
return (
<div style={{ width }} className="Slider__Item">
{children}
</div>
)
}
}
export default SliderItem
html, body, * {
margin: 0;
padding: 0;
}
.Slider__Wrapper img {
width: 100%;
max-width: 100%;
height: auto;
}
.Slider {
overflow: hidden;
scroll-behavior: smooth;
}
.Slider__Content {
transform: translateX(0%);
overflow: hidden;
display: flex;
}
.Slider__Item {
word-wrap: break-word;
overflow: hidden;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment