微件:Banner
来自EaseCation Wiki
更多操作
<style>
#carousel- {
position: relative;
width: 100%;
box-sizing: border-box;
}
#carousel- .carousel-track {
display: flex;
height: 100%;
transition: transform 0.5s ease-in-out;
}
#carousel- .slide {
flex: 0 0 100%;
position: relative;
height: 100%;
overflow: hidden;
}
#carousel- .slide-link {
display: block;
width: 100%;
height: 100%;
text-decoration: none;
color: inherit;
}
#carousel- .slide img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
#carousel- .slide-caption {
position: absolute;
left: 0;
right: 0;
bottom: 0;
padding: 20px 30px;
background: linear-gradient(to top, rgba(0,0,0,0.7), transparent);
color: #fff;
pointer-events: none;
}
#carousel- .slide-caption h2 {
font-size: 24px;
margin-bottom: 6px;
margin-top: 0;
}
#carousel- .slide-caption p {
font-size: 14px;
margin: 0;
opacity: 0.9;
}
#carousel- .carousel-btn {
position: absolute;
top: 50%;
transform: translateY(-50%);
width: 44px;
height: 44px;
border: none;
border-radius: 50%;
background: rgba(255, 255, 255, 0.7);
color: #333;
font-size: 22px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s;
z-index: 10;
user-select: none;
padding: 0;
line-height: 1;
}
#carousel- .carousel-btn:hover {
background: rgba(255, 255, 255, 0.95);
box-shadow: 0 2px 10px rgba(0,0,0,0.2);
}
#carousel- .carousel-btn.prev {
left: 16px;
}
#carousel- .carousel-btn.next {
right: 16px;
}
#carousel- .carousel-indicators {
position: absolute;
bottom: 16px;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: 8px;
z-index: 10;
}
#carousel- .indicator {
width: 10px;
height: 10px;
border-radius: 50%;
background: rgba(255, 255, 255, 0.6);
cursor: pointer;
transition: all 0.3s;
border: none;
padding: 0;
}
#carousel- .indicator.active {
background: #fff;
width: 24px;
border-radius: 5px;
}
@media (max-width: 600px) {
#carousel- .carousel-btn {
width: 36px;
height: 36px;
font-size: 18px;
}
#carousel- .slide-caption h2 {
font-size: 18px;
}
}
</style>
<script>
{
// 解析传入的 JSON 数据
const data = JSON.parse("");
// 获取容器内各元素
const container = document.getElementById('carousel-');
const track = document.getElementById('carousel-track-');
const prevBtn = document.getElementById('carousel-prev-');
const nextBtn = document.getElementById('carousel-next-');
const indicatorsContainer = document.getElementById('carousel-indicators-');
// 配置默认值
const config = {
slides: data.slides || [],
autoplay: data.autoplay !== undefined ? data.autoplay : true,
interval: data.interval || 3000,
showArrows: data.showArrows !== undefined ? data.showArrows : true,
showIndicators: data.showIndicators !== undefined ? data.showIndicators : true,
showCaptions: data.showCaptions !== undefined ? data.showCaptions : true,
width: data.width || '100%',
height: data.height || '400px',
objectFit: data.objectFit || 'cover',
borderRadius: data.borderRadius || '12px',
loop: data.loop !== undefined ? data.loop : true
};
// 应用样式配置
container.style.width = config.width;
container.style.height = config.height;
container.style.borderRadius = config.borderRadius;
prevBtn.style.display = config.showArrows ? 'flex' : 'none';
nextBtn.style.display = config.showArrows ? 'flex' : 'none';
indicatorsContainer.style.display = config.showIndicators ? 'flex' : 'none';
const totalSlides = config.slides.length;
if (totalSlides === 0) {
container.innerHTML = '
暂无图片
';
} else {
let currentIndex = 0;
let autoPlayTimer = null;
// 生成幻灯片 DOM
config.slides.forEach((slide, index) => {
const slideDiv = document.createElement('div');
slideDiv.className = 'slide';
const img = document.createElement('img');
img.src = slide.image || ;
img.alt = slide.title || '轮播图';
img.style.objectFit = config.objectFit;
if (slide.link) {
const link = document.createElement('a');
link.href = slide.link;
link.className = 'slide-link';
link.target = '_blank';
link.appendChild(img);
if (config.showCaptions && (slide.title || slide.description)) {
const caption = document.createElement('div');
caption.className = 'slide-caption';
if (slide.title) {
const h2 = document.createElement('h2');
h2.textContent = slide.title;
caption.appendChild(h2);
}
if (slide.description) {
const p = document.createElement('p');
p.textContent = slide.description;
caption.appendChild(p);
}
link.appendChild(caption);
}
slideDiv.appendChild(link);
} else {
slideDiv.appendChild(img);
if (config.showCaptions && (slide.title || slide.description)) {
const caption = document.createElement('div');
caption.className = 'slide-caption';
if (slide.title) {
const h2 = document.createElement('h2');
h2.textContent = slide.title;
caption.appendChild(h2);
}
if (slide.description) {
const p = document.createElement('p');
p.textContent = slide.description;
caption.appendChild(p);
}
slideDiv.appendChild(caption);
}
}
track.appendChild(slideDiv);
});
// 生成指示点
if (config.showIndicators) {
config.slides.forEach((_, index) => {
const dot = document.createElement('button');
dot.className = 'indicator' + (index === 0 ? ' active' : );
dot.setAttribute('aria-label', `切换到第 ${index + 1} 张`);
dot.addEventListener('click', () => {
goToSlide(index);
resetAutoPlay();
});
indicatorsContainer.appendChild(dot);
});
}
function goToSlide(index) {
if (config.loop) {
if (index < 0) {
index = totalSlides - 1;
} else if (index >= totalSlides) {
index = 0;
}
} else {
if (index < 0) index = 0;
if (index >= totalSlides) index = totalSlides - 1;
prevBtn.disabled = index === 0;
nextBtn.disabled = index === totalSlides - 1;
}
currentIndex = index;
track.style.transform = `translateX(-${currentIndex * 100}%)`;
const dots = indicatorsContainer.querySelectorAll('.indicator');
dots.forEach((dot, i) => {
dot.classList.toggle('active', i === currentIndex);
});
}
function nextSlide() {
goToSlide(currentIndex + 1);
}
function prevSlide() {
goToSlide(currentIndex - 1);
}
function startAutoPlay() {
if (!config.autoplay || totalSlides <= 1) return;
if (autoPlayTimer) clearInterval(autoPlayTimer);
autoPlayTimer = setInterval(nextSlide, config.interval);
}
function stopAutoPlay() {
if (autoPlayTimer) {
clearInterval(autoPlayTimer);
autoPlayTimer = null;
}
}
function resetAutoPlay() {
stopAutoPlay();
startAutoPlay();
}
nextBtn.addEventListener('click', () => {
nextSlide();
resetAutoPlay();
});
prevBtn.addEventListener('click', () => {
prevSlide();
resetAutoPlay();
});
container.addEventListener('mouseenter', stopAutoPlay);
container.addEventListener('mouseleave', startAutoPlay);
document.addEventListener('keydown', (e) => {
if (e.key === 'ArrowLeft') {
prevSlide();
resetAutoPlay();
} else if (e.key === 'ArrowRight') {
nextSlide();
resetAutoPlay();
}
});
let touchStartX = 0;
let touchEndX = 0;
container.addEventListener('touchstart', (e) => {
touchStartX = e.changedTouches[0].screenX;
stopAutoPlay();
}, { passive: true });
container.addEventListener('touchend', (e) => {
touchEndX = e.changedTouches[0].screenX;
const diff = touchStartX - touchEndX;
if (Math.abs(diff) > 50) {
if (diff > 0) {
nextSlide();
} else {
prevSlide();
}
resetAutoPlay();
} else {
startAutoPlay();
}
}, { passive: true });
// 初始化
goToSlide(0);
if (config.loop === false) {
prevBtn.disabled = currentIndex === 0;
}
startAutoPlay();
}
}
</script>