Instantly share code, notes, and snippets.

Embed
What would you like to do?
Source code for "How to write JavaScript components with jQuery"
import $ from 'jquery'
import './styles.scss'
import CarouselControls from '../CarouselControls'
import CarouselDots from '../CarouselDots'
import CarouselSlider from '../CarouselSlider'
import mod from '../../lib/mod'
class CarouselBlock {
constructor({root}) {
this.root = $(root)
this.slides = new CarouselSlider({
root: this.root.children('.carousel-slider')[0]
})
this.controls = new CarouselControls({
root: this.root.children('.carousel-controls')[0]
})
this.dots = new CarouselDots({
root: this.root.children('.carousel-dots')[0]
})
this.currentIndex = 0
this.controls.on('clicknext', () => this.nextSlide())
this.controls.on('clickprev', () => this.prevSlide())
this.dots.on('clickdot', index => this.slideTo(index))
}
slideTo(index) {
this.slides.slideTo(index)
this.dots.highlightDot(index)
this.currentIndex = index
}
nextSlide() {
let nextIndex = mod(this.currentIndex + 1, this.slides.slideCount)
this.slideTo(nextIndex)
}
prevSlide() {
let prevIndex = mod(this.currentIndex - 1, this.slides.slideCount)
this.slideTo(prevIndex)
}
}
export default CarouselBlock
@import "vertical-rhythm";
.carousel-block {
margin: vr(5) auto;
position: relative;
width: 768px;
.carousel-slider {
margin-bottom: vr(1);
}
.carousel-controls {
position: absolute;
top: 50%;
transform: translateY(-50%);
width: 100%;
}
}
import $ from 'jquery'
import EventEmitter from 'eventemitter3'
import './styles.scss'
class CarouselControls extends EventEmitter {
constructor({root}) {
super()
this.root = $(root)
this.buttons = this.root.children('.carousel-controls__button')
this.buttons.on('click', ev => this._handleClick(ev))
}
_handleClick(ev) {
ev.preventDefault()
const target = $(ev.target)
if (target.hasClass('carousel-controls__next')) {
this.emit('clicknext')
} else {
this.emit('clickprev')
}
}
}
export default CarouselControls
@import "button-reset";
@import "vertical-rhythm";
.carousel-controls {
display: flex;
flex-direction: row;
justify-content: space-between;
&__button {
@extend %button-reset;
background-color: rgba(#000, 0.1);
color: #fff;
height: vr(2);
width: vr(3);
}
}
import $ from 'jquery'
import EventEmitter from 'eventemitter3'
import './styles.scss'
class CarouselDots extends EventEmitter {
constructor({root}) {
super()
this.root = $(root)
this.dots = this.root.children('.carousel-dots__dot')
this.dots.on('click', ev => this._handleClick(ev))
}
_handleClick(ev) {
ev.preventDefault()
const index = this.dots.index(ev.target)
this.highlightDot(index)
this.emit('clickdot', index)
}
highlightDot(index) {
this.dots.removeClass('carousel-dots__dot--active')
this.dots.eq(index).addClass('carousel-dots__dot--active')
}
}
export default CarouselDots
@import "button-reset";
@import "vertical-rhythm";
.carousel-dots {
display: flex;
flex-direction: row;
justify-content: center;
&__dot {
@extend %button-reset;
background-color: rgba(#000, 0.2);
border-radius: 50%;
height: vr(0.5);
margin: 0 vr(0.5);
transition: background-color 0.4s ease;
width: vr(0.5);
&--active {
background-color: rgba(#000, 0.5);
}
}
}
import $ from 'jquery'
import './styles.scss'
class CarouselSlider {
constructor({root}) {
this.root = $(root)
this.slideList = this.root.children('.carousel-slider__slide-list')
this.slides = this.slideList.children('.carousel-slider__slide')
}
get slideCount() {
return this.slides.length
}
slideTo(index) {
this.slideList.css({transform: `translateX(-${100 * index}%)`});
}
}
export default CarouselSlider
.carousel-slider {
overflow: hidden;
&__slide-list {
display: flex;
flex-direction: row;
list-style-type: none;
margin: 0;
padding: 0;
transform: translateX(0);
transition: transform 0.4s ease;
}
&__slide {
flex: 1 0 100%;
img {
display: block;
max-width: 100%;
}
}
}
// Modulo that works with negative numbers
export default function mod(n, m) {
return ((n % m) + m) % m;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment