拖拽实现3
import React, { useState, useRef, useEffect } from ‘react’;
import ‘./ImageList.css’;
const ImageList = () => {
const images = [
‘https://picsum.photos/300/200?random=1’,
‘https://picsum.photos/300/200?random=2’,
‘https://picsum.photos/300/200?random=3’,
‘https://picsum.photos/300/200?random=4’,
‘https://picsum.photos/300/200?random=5’,
‘https://picsum.photos/300/200?random=6’,
];
const listRef = useRef(null);
const [isDragging, setIsDragging] = useState(false);
const [startX, setStartX] = useState(0);
const [translateX, setTranslateX] = useState(0);
const [lastTranslateX, setLastTranslateX] = useState(0);
const [isBouncing, setIsBouncing] = useState(false);
// 获取边界值
const getBoundaries = () => {
if (!listRef.current) return { minTranslate: 0, maxTranslate: 0 };
const maxTranslate = 0;
const minTranslate = -(listRef.current.scrollWidth - listRef.current.parentElement.offsetWidth);
return { minTranslate, maxTranslate };
};
// 处理开始拖动
const handleStart = (clientX) => {
setIsDragging(true);
setStartX(clientX - lastTranslateX);
setIsBouncing(false); // 取消回弹状态
};
// 处理拖动移动
const handleMove = (clientX) => {
if (!isDragging) return;
const newTranslateX = clientX - startX;
const { minTranslate, maxTranslate } = getBoundaries();
// 允许稍微越界以模拟拉伸效果
if (newTranslateX > maxTranslate) {
// 右边界,添加阻力效果
const overflow = newTranslateX - maxTranslate;
setTranslateX(maxTranslate + overflow * 0.3); // 0.3为阻力系数
} else if (newTranslateX < minTranslate) {
// 左边界,添加阻力效果
const overflow = newTranslateX - minTranslate;
setTranslateX(minTranslate + overflow * 0.3);
} else {
setTranslateX(newTranslateX);
}
};
// 处理拖动结束
const handleEnd = () => {
setIsDragging(false);
const { minTranslate, maxTranslate } = getBoundaries();
// 检查是否越界并触发回弹
if (translateX > maxTranslate) {
setIsBouncing(true);
setTranslateX(maxTranslate);
setLastTranslateX(maxTranslate);
} else if (translateX < minTranslate) {
setIsBouncing(true);
setTranslateX(minTranslate);
setLastTranslateX(minTranslate);
} else {
setLastTranslateX(translateX);
}
};
// 鼠标事件
const handleMouseDown = (e) => handleStart(e.clientX);
const handleMouseMove = (e) => handleMove(e.clientX);
const handleMouseUp = () => handleEnd();
// 触摸事件
const handleTouchStart = (e) => handleStart(e.touches[0].clientX);
const handleTouchMove = (e) => handleMove(e.touches[0].clientX);
const handleTouchEnd = () => handleEnd();
// 添加和清理事件监听器
useEffect(() => {
const ref = listRef.current;
ref.addEventListener(‘mousedown’, handleMouseDown);
ref.addEventListener(‘touchstart’, handleTouchStart);
window.addEventListener(‘mousemove’, handleMouseMove);
window.addEventListener(‘touchmove’, handleTouchMove);
window.addEventListener(‘mouseup’, handleMouseUp);
window.addEventListener(‘touchend’, handleTouchEnd);
return () => {
ref.removeEventListener('mousedown', handleMouseDown);
ref.removeEventListener('touchstart', handleTouchStart);
window.removeEventListener('mousemove', handleMouseMove);
window.removeEventListener('touchmove', handleTouchMove);
window.removeEventListener('mouseup', handleMouseUp);
window.removeEventListener('touchend', handleTouchEnd);
};
}, [isDragging, startX, translateX]);
return (
<div
ref={listRef}
className={
image-list ${isDragging ? 'dragging' : ''} ${isBouncing ? 'bouncing' : ''}
}
style={{ transform:
translateX(${translateX}px)
}}
>
{images.map((src, index) => (
<img src={src} alt={
Image ${index + 1}
} />
))}
);
};
export default ImageList;