Bonjour mes amis! J'ai décidé de revenir au sujet des curseurs. Cet article a servi d'inspiration . Un article sur le générateur de galerie d'images avec un curseur intégré est ici .Le curseur que nous allons écrire fonctionne sur le principe d'un jeu de cartes sans fin ou d'une pile d'images. L'image du haut est supprimée dans l'une des trois directions - gauche, droite ou haut. L'image supprimée est remplacée par l'image suivante, et ainsi de suite à l'infini. Vous pouvez télécharger vos images ou utiliser les images par défaut.Pour enregistrer les gestes (touches) et déplacer (glisser-déposer) hammer.js est utilisé . Cette bibliothèque vous permet de détecter à la fois les clics de souris et les contacts avec les doigts.Alors allons-y.Le balisage ressemble à ceci:<input type="file" multiple>
<button>build carousel</button>
<div></div>
Nous avons une «entrée» pour charger les images, un bouton pour créer un carrousel et un conteneur pour les cartes.Ajoutez quelques styles:body {
margin: 0;
overflow: hidden;
}
div {
width: 100%;
height: 100vh;
position: relative;
}
img {
width: 320px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) scale(0.95);
box-shadow: 0px 4px 4px 0px rgba(0, 0, 0, 0.1);
}
Rien de spécial ici: les images ont une largeur de 320 pixels, centrées les unes sur les autres.Nous passons à JS. Je vais donner tout le code. N'ayez pas peur du nombre de lignes, tout est assez simple, sauf, peut-être, le calcul des positions et des coordonnées. Presque chaque ligne a un commentaire.let button = document.querySelector('button')
let input = document.querySelector('input')
let files
let i = 0
button.addEventListener('click', () => {
files = input.files
document.body.removeChild(input)
document.body.removeChild(button)
let board = document.querySelector('div')
let carousel = new Carousel(board)
})
class Carousel {
constructor(element) {
this.board = element
this.push()
i++
this.push()
this.handle()
}
handle() {
this.cards = this.board.querySelectorAll('img')
this.topCard = this.cards[this.cards.length - 1]
this.nextCard = this.cards[this.cards.length - 2]
if (this.cards.length > 0) {
this.topCard.style.transform =
'translate(-50%, -50%) rotate(0deg) scale(1)'
this.hammer = new Hammer(this.topCard)
this.hammer.add(new Hammer.Tap())
this.hammer.add(new Hammer.Pan({
position: Hammer.position_ALL,
threshold: 0
}))
this.hammer.on('tap', (e) => {
this.onTap(e)
})
this.hammer.on('pan', (e) => {
this.onPan(e)
})
}
}
onTap(e) {
let propX = (e.center.x - e.target.getBoundingClientRect().left) / e.target.clientWidth
let rotateY = 15 * (propX < 0.05 ? -1 : 1)
this.topCard.style.transition = 'transform 100ms ease-out'
this.topCard.style.transform =
'translate(-50%, -50%) rotateX(0deg) rotateY(' + rotateY + 'deg) scale(1)'
setTimeout(() => {
this.topCard.style.transform =
'translate(-50%, -50%) rotate(0deg) scale(1)'
}, 100)
}
onPan(e) {
if (!this.isPanning) {
this.isPanning = true
this.topCard.style.transition = null
if (this.nextCard) this.nextCard.style.transition = null
let style = window.getComputedStyle(this.topCard)
let mx = style.transform.match(/^matrix\((.+)\)$/)
this.startPosX = mx ? parseFloat(mx[1].split(', ')[4]) : 0
this.startPosY = mx ? parseFloat(mx[1].split(', ')[5]) : 0
let bounds = this.topCard.getBoundingClientRect()
this.isDraggingFrom =
(e.center.y - bounds.top) > this.topCard.clientHeight / 2 ? -1 : 1
}
let posX = e.deltaX + this.startPosX
let posY = e.deltaY + this.startPosY
let propX = e.deltaX / this.board.clientWidth
let propY = e.deltaY / this.board.clientHeight
let dirX = e.deltaX < 0 ? -1 : 1
let deg = this.isDraggingFrom * dirX * Math.abs(propX) * 45
let scale = (95 + (5 * Math.abs(propX))) / 100
this.topCard.style.transform =
'translateX(' + posX + 'px) translateY(' + posY + 'px) rotate(' + deg + 'deg) scale(1)'
if (this.nextCard) this.nextCard.style.transform =
'translate(-50%, -50%) rotate(0deg) scale(' + scale + ')'
if (e.isFinal) {
this.isPanning = false
let successful = false
this.topCard.style.transition = 'transform 200ms ease-out'
if (this.nextCard) this.nextCard.style.transition = 'transform 100ms linear'
if (propX > 0.25 && e.direction == Hammer.DIRECTION_RIGHT) {
successful = true
posX = this.board.clientWidth
} else if (propX < -0.25 && e.direction == Hammer.DIRECTION_LEFT) {
successful = true
posX = -(this.board.clientWidth + this.topCard.clientWidth)
} else if (propY < -0.25 && e.direction == Hammer.DIRECTION_UP) {
successful = true
posY = -(this.board.clientHeight + this.topCard.clientHeight)
}
if (successful) {
this.topCard.style.transform =
'translateX(' + posX + 'px) translateY(' + posY + 'px) rotate(' + deg + 'deg)'
setTimeout(() => {
this.board.removeChild(this.topCard)
i++
if (i === files.length) i = 0
this.push()
this.handle()
}, 200)
} else {
this.topCard.style.transform =
'translate(-50%, -50%) rotate(0deg) scale(1)'
if (this.nextCard) this.nextCard.style.transform =
'translate(-50%, -50%) rotate(0deg) scale(0.95)'
}
}
}
push() {
let card = document.createElement('img')
if (files.length === 0) {
card.src = 'https://picsum.photos/320/320/?random=' +
Math.round(Math.random() * 1000000) +
')'
} else {
card.src = URL.createObjectURL(files[i])
}
if (this.board.firstChild) {
this.board.insertBefore(card, this.board.firstChild)
} else {
this.board.append(card)
}
}
}
→ GithubMerci de votre attention.