实现一个多图轮播功能
- 如图
js部分
class PerfectCarousel {
constructor(containerId, data, options = {}) {
// 初始化配置
this.options = {
slideWidth: 295,
slideHeight: 240,
gap: 10,
slidesToShow: 4,
autoPlay: true,
interval: 3000,
resumeDelay: 5000,
...options
};
// 数据克隆
this.originalData = data;
this.data = [...data, ...data, ...data];
this.currentIndex = data.length;
// 状态控制
this.isPaused = false;
this.userActionTimer = null;
this.isPausedByHover = false;
this.init(containerId);
if (this.options.autoPlay) this.startAutoPlay();
}
init(containerId) {
// 容器初始化
this.container = document.getElementById(containerId);
if (!this.container) {
console.error(`Container #${containerId} not found`);
return;
}
// 清空容器
this.container.innerHTML = '';
this.container.style.position = 'relative';
this.container.style.width = `${this.options.slideWidth * this.options.slidesToShow +
this.options.gap * (this.options.slidesToShow - 1)}px`;
this.container.style.height = `${this.options.slideHeight}px`;
this.container.style.overflow = 'hidden';
// 创建轨道
this.track = document.createElement('div');
this.track.className = 'pc-track';
this.track.style.display = 'flex';
this.track.style.height = '100%';
this.track.style.willChange = 'transform';
this.container.appendChild(this.track);
// 创建轮播项
this.data.forEach((item, i) => {
const slide = document.createElement('div');
slide.className = 'pc-slide';
slide.style.width = `${this.options.slideWidth}px`;
slide.style.marginRight = `${this.options.gap}px`;
slide.style.flexShrink = '0';
slide.style.position = 'relative';
const link = document.createElement('a');
link.className = 'pc-link';
link.href = item.target || '#';
link.target = '_blank';
const img = document.createElement('img');
img.className = 'pc-image';
img.src = item.url;
img.alt = item.title;
img.style.width = '100%';
img.style.height = '100%';
img.style.objectFit = 'cover';
img.style.cursor = 'pointer';
const caption = document.createElement('div');
caption.className = 'pc-caption';
caption.textContent = item.title;
caption.style.position = 'absolute';
caption.style.bottom = '0';
caption.style.width = '100%';
caption.style.height = '40px';
caption.style.background = 'rgba(0,0,0,0.6)';
caption.style.color = 'white';
caption.style.display = 'flex';
caption.style.alignItems = 'center';
caption.style.justifyContent = 'center';
link.appendChild(img);
slide.appendChild(link);
slide.appendChild(caption);
this.track.appendChild(slide);
});
// 创建导航按钮
this.prevBtn = document.createElement('button');
this.prevBtn.className = 'pc-btn pc-prev';
this.prevBtn.innerHTML = '❮';
this.prevBtn.style.position = 'absolute';
this.prevBtn.style.top = '50%';
this.prevBtn.style.left = '0';
this.prevBtn.style.transform = 'translateY(-50%)';
this.prevBtn.style.width = '45px';
this.prevBtn.style.height = '60px';
this.prevBtn.style.background = 'rgba(0,0,0,0.6)';
this.prevBtn.style.color = 'white';
this.prevBtn.style.border = 'none';
this.prevBtn.style.fontSize = '24px';
this.prevBtn.style.cursor = 'pointer';
this.prevBtn.style.zIndex = '10';
this.container.appendChild(this.prevBtn);
this.nextBtn = document.createElement('button');
this.nextBtn.className = 'pc-btn pc-next';
this.nextBtn.innerHTML = '❯';
this.nextBtn.style.position = 'absolute';
this.nextBtn.style.top = '50%';
this.nextBtn.style.right = '0';
this.nextBtn.style.transform = 'translateY(-50%)';
this.nextBtn.style.width = '45px';
this.nextBtn.style.height = '60px';
this.nextBtn.style.background = 'rgba(0,0,0,0.6)';
this.nextBtn.style.color = 'white';
this.nextBtn.style.border = 'none';
this.nextBtn.style.fontSize = '24px';
this.nextBtn.style.cursor = 'pointer';
this.nextBtn.style.zIndex = '10';
this.container.appendChild(this.nextBtn);
// 事件绑定
this.prevBtn.addEventListener('click', () => {
this.handleUserAction();
this.prev();
});
this.nextBtn.addEventListener('click', () => {
this.handleUserAction();
this.next();
});
this.container.addEventListener('mouseenter', () => {
this.isPausedByHover = true;
this.pause();
});
this.container.addEventListener('mouseleave', () => {
this.isPausedByHover = false;
this.resume();
});
this.track.addEventListener('transitionend', () => this.checkPosition());
// 初始位置
this.updatePosition(true);
}
handleUserAction() {
this.pause();
clearTimeout(this.userActionTimer);
this.userActionTimer = setTimeout(() => {
if (!this.isPausedByHover) this.resume();
}, this.options.resumeDelay);
}
pause() {
if (!this.isPaused) {
clearInterval(this.autoPlayInterval);
this.isPaused = true;
}
}
resume() {
if (this.isPaused) {
this.startAutoPlay();
this.isPaused = false;
}
}
startAutoPlay() {
clearInterval(this.autoPlayInterval);
this.autoPlayInterval = setInterval(() => {
if (!this.isPaused) this.next();
}, this.options.interval);
}
next() {
this.currentIndex++;
this.updatePosition();
}
prev() {
this.currentIndex--;
this.updatePosition();
}
updatePosition(instant = false) {
const offset = -this.currentIndex * (this.options.slideWidth + this.options.gap);
this.track.style.transition = instant ? 'none' : 'transform 0.5s ease';
this.track.style.transform = `translateX(${offset}px)`;
}
checkPosition() {
if (this.currentIndex <= 0) {
this.currentIndex = this.originalData.length;
this.updatePosition(true);
}
else if (this.currentIndex >= this.originalData.length * 2) {
this.currentIndex = this.originalData.length;
this.updatePosition(true);
}
}
}
css部分
.pc-container {
position: relative;
width: 1200px; /* 295*4 + 10*3 */
height: 240px;
overflow: hidden;
margin: 0 auto;
}
.pc-track {
display: flex;
height: 100%;
will-change: transform;
}
.pc-slide {
flex-shrink: 0;
position: relative;
}
.pc-image {
width: 100%;
height: 100%;
object-fit: cover;
cursor: pointer;
}
.pc-caption {
position: absolute;
bottom: 0;
width: 100%;
height: 40px;
background: rgba(0,0,0,0.6);
color: white;
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
}
.pc-btn {
position: absolute;
top: 50%;
transform: translateY(-50%);
width: 45px;
height: 60px;
background: rgba(0,0,0,0.6);
color: white;
border: none;
font-size: 24px;
cursor: pointer;
z-index: 10;
display: flex;
align-items: center;
justify-content: center;
}
.pc-prev { left: 0; }
.pc-next { right: 0; }
.pc-btn:hover {
background: rgba(0,0,0,0.8);
transform: translateY(-50%) scale(1.05);
}
.pc-container:hover .pc-image {
opacity: 0.9;
transition: opacity 0.3s;
}
使用方式
<div id="carouseContainer" class="pc-container"></div>
const myCarousel = new PerfectCarousel('carouseContainer', carouselData, {
autoPlay: true,
interval: 3000,
showButtons: true
});
-
carouselData数据格式
[{url:'图片路径',title:'轮播标题',target:'点击图片的跳转链接'},...]