<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>水平拖拽切换图片特效</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: Arial, sans-serif;
background-color: #f5f5f5;
padding: 20px;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
background-color: white;
border-radius: 10px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
h1 {
text-align: center;
margin-bottom: 30px;
color: #333;
}
.slider-container {
position: relative;
width: 100%;
overflow: hidden;
margin-bottom: 30px;
border-radius: 8px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
.slider {
display: flex;
transition: transform 0.3s ease-out;
height: 400px;
cursor: grab;
}
.slider.dragging {
transition: none;
cursor: grabbing;
}
.slide {
min-width: 100%;
height: 100%;
position: relative;
}
.slide img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
.slide-caption {
position: absolute;
bottom: 0;
left: 0;
right: 0;
background: rgba(0, 0, 0, 0.6);
color: white;
padding: 15px;
text-align: center;
}
.slider-nav {
display: flex;
justify-content: center;
margin-top: 15px;
}
.slider-dot {
width: 12px;
height: 12px;
border-radius: 50%;
background-color: #ccc;
margin: 0 5px;
cursor: pointer;
transition: background-color 0.3s;
}
.slider-dot.active {
background-color: #333;
}
.content {
line-height: 1.6;
margin-bottom: 20px;
}
.footer {
text-align: center;
margin-top: 30px;
padding-top: 20px;
border-top: 1px solid #eee;
color: #666;
}
.footer a {
color: #0066cc;
text-decoration: none;
}
.footer a:hover {
text-decoration: underline;
}
</style>
</head>
<body>
<div class="container">
<h1>水平拖拽切换图片特效</h1>
<div class="slider-container">
<div class="slider">
<div class="slide">
<img src="https://source.unsplash.com/random/800x400?nature" alt="自然风景">
<div class="slide-caption">美丽的自然风景</div>
</div>
<div class="slide">
<img src="https://source.unsplash.com/random/800x400?city" alt="城市风光">
<div class="slide-caption">现代城市风光</div>
</div>
<div class="slide">
<img src="https://source.unsplash.com/random/800x400?animal" alt="动物世界">
<div class="slide-caption">可爱的动物世界</div>
</div>
<div class="slide">
<img src="https://source.unsplash.com/random/800x400?food" alt="美食">
<div class="slide-caption">诱人的美食</div>
</div>
</div>
</div>
<div class="slider-nav">
<div class="slider-dot active" data-index="0"></div>
<div class="slider-dot" data-index="1"></div>
<div class="slider-dot" data-index="2"></div>
<div class="slider-dot" data-index="3"></div>
</div>
<div class="content">
<p>这是一个水平拖拽切换图片的特效演示。您可以通过鼠标拖拽或者点击下方的小圆点来切换图片。</p>
<p>这个特效完全使用原生JavaScript实现,不依赖任何第三方库。</p>
<p>如果您对网页特效感兴趣,</p>
<p>拖拽切换图片是一种常见的网页交互方式,适用于展示产品、相册等多种场景。</p>
</div>
<div class="footer">
<p>© 2023 水平拖拽图片特效演示</p>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
const slider = document.querySelector('.slider');
const slides = document.querySelectorAll('.slide');
const dots = document.querySelectorAll('.slider-dot');
const sliderContainer = document.querySelector('.slider-container');
let currentIndex = 0;
let startPos = 0;
let currentTranslate = 0;
let prevTranslate = 0;
let isDragging = false;
let animationID;
// 设置初始位置
setSliderPosition();
// 鼠标/触摸事件
sliderContainer.addEventListener('mousedown', startDrag);
sliderContainer.addEventListener('touchstart', startDrag);
sliderContainer.addEventListener('mousemove', drag);
sliderContainer.addEventListener('touchmove', drag);
sliderContainer.addEventListener('mouseup', endDrag);
sliderContainer.addEventListener('mouseleave', endDrag);
sliderContainer.addEventListener('touchend', endDrag);
// 防止拖动时选中文本
sliderContainer.addEventListener('dragstart', e => e.preventDefault());
// 点击圆点导航
dots.forEach(dot => {
dot.addEventListener('click', function() {
const index = parseInt(this.getAttribute('data-index'));
goToSlide(index);
});
});
function startDrag(e) {
if (e.type === 'touchstart') {
startPos = e.touches[0].clientX;
} else {
startPos = e.clientX;
e.preventDefault();
}
isDragging = true;
slider.classList.add('dragging');
// 取消动画
cancelAnimationFrame(animationID);
}
function drag(e) {
if (!isDragging) return;
let currentPosition;
if (e.type === 'touchmove') {
currentPosition = e.touches[0].clientX;
} else {
currentPosition = e.clientX;
}
const diff = currentPosition - startPos;
currentTranslate = prevTranslate + diff;
// 限制拖动范围
const maxTranslate = 0;
const minTranslate = -(slides.length - 1) * sliderContainer.offsetWidth;
if (currentTranslate > maxTranslate + 100) {
currentTranslate = maxTranslate + 100;
} else if (currentTranslate < minTranslate - 100) {
currentTranslate = minTranslate - 100;
}
setSliderPosition();
}
function endDrag() {
if (!isDragging) return;
isDragging = false;
slider.classList.remove('dragging');
// 计算最终位置
const movedBy = currentTranslate - prevTranslate;
if (movedBy < -100 && currentIndex < slides.length - 1) {
currentIndex += 1;
} else if (movedBy > 100 && currentIndex > 0) {
currentIndex -= 1;
}
goToSlide(currentIndex);
}
function setSliderPosition() {
slider.style.transform = `translateX(${currentTranslate}px)`;
}
function goToSlide(index) {
currentIndex = index;
prevTranslate = -currentIndex * sliderContainer.offsetWidth;
currentTranslate = prevTranslate;
// 添加平滑过渡
slider.style.transition = 'transform 0.3s ease-out';
setSliderPosition();
// 更新导航点
updateDots();
// 过渡结束后移除过渡效果
slider.addEventListener('transitionend', () => {
slider.style.transition = 'none';
}, { once: true });
}
function updateDots() {
dots.forEach((dot, index) => {
if (index === currentIndex) {
dot.classList.add('active');
} else {
dot.classList.remove('active');
}
});
}
// 响应窗口大小变化
window.addEventListener('resize', function() {
prevTranslate = -currentIndex * sliderContainer.offsetWidth;
currentTranslate = prevTranslate;
setSliderPosition();
});
});
</script>
</body>
</html>