朋友们,美好的一天!我决定返回到滑块主题。本文作为启示。有关带内置滑块的图库生成器的文章,请参见此处。我们将要写的滑块是基于无休止的卡片组或图像堆栈的原理工作的。顶部图像沿三个方向之一(左,右或上)被丢弃。丢弃的图像将替换为以下图像,依此类推直至无穷大。您可以上传图像或使用默认图像。为了注册手势(触摸)和移动(拖放),使用Hammer.js。该库可让您检测鼠标单击和手指触摸。所以走吧标记如下所示:<input type="file" multiple>
<button>build carousel</button>
<div></div>
我们有一个用于加载图像的“输入”,一个用于创建轮播的按钮和一个用于存储卡片的容器。添加一些样式: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);
}
这里没什么特别的:图像宽320像素,彼此上下居中。我们传递给JS。我将给出整个代码。不要害怕行数,除了可能计算位置和坐标之外,一切都非常简单。几乎每一行都有注释。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)
}
}
}
→ Github谢谢您的关注。