下载按钮可拖动

This commit is contained in:
mtvpls
2026-02-26 10:08:28 +08:00
parent 1f87e69eb9
commit 9906bb7ea9

View File

@@ -1,20 +1,131 @@
'use client';
import React from 'react';
import React, { useState, useEffect } from 'react';
import { useDownload } from '@/contexts/DownloadContext';
export function DownloadBubble() {
const { tasks, downloadingCount, setShowDownloadPanel } = useDownload();
// 拖动状态
const [position, setPosition] = useState({ x: 0, y: 0 });
const [isDragging, setIsDragging] = useState(false);
const [dragOffset, setDragOffset] = useState({ x: 0, y: 0 });
// 初始化位置(右下角)
useEffect(() => {
const initPosition = () => {
setPosition({
x: window.innerWidth - 80,
y: window.innerHeight - 80
});
};
initPosition();
window.addEventListener('resize', initPosition);
return () => window.removeEventListener('resize', initPosition);
}, []);
// 处理拖动
useEffect(() => {
const handleMouseMove = (e: MouseEvent) => {
if (!isDragging) return;
const newX = e.clientX - dragOffset.x;
const newY = e.clientY - dragOffset.y;
// 限制在视口范围内
const maxX = window.innerWidth - 64;
const maxY = window.innerHeight - 64;
setPosition({
x: Math.max(0, Math.min(newX, maxX)),
y: Math.max(0, Math.min(newY, maxY))
});
};
const handleTouchMove = (e: TouchEvent) => {
if (!isDragging) return;
e.preventDefault();
const touch = e.touches[0];
const newX = touch.clientX - dragOffset.x;
const newY = touch.clientY - dragOffset.y;
// 限制在视口范围内
const maxX = window.innerWidth - 64;
const maxY = window.innerHeight - 64;
setPosition({
x: Math.max(0, Math.min(newX, maxX)),
y: Math.max(0, Math.min(newY, maxY))
});
};
const handleEnd = () => {
setIsDragging(false);
};
if (isDragging) {
document.addEventListener('mousemove', handleMouseMove);
document.addEventListener('mouseup', handleEnd);
document.addEventListener('touchmove', handleTouchMove, { passive: false });
document.addEventListener('touchend', handleEnd);
}
return () => {
document.removeEventListener('mousemove', handleMouseMove);
document.removeEventListener('mouseup', handleEnd);
document.removeEventListener('touchmove', handleTouchMove);
document.removeEventListener('touchend', handleEnd);
};
}, [isDragging, dragOffset]);
const handleMouseDown = (e: React.MouseEvent<HTMLButtonElement>) => {
if (e.button !== 0) return;
setIsDragging(true);
const rect = e.currentTarget.getBoundingClientRect();
setDragOffset({
x: e.clientX - rect.left,
y: e.clientY - rect.top
});
};
const handleTouchStart = (e: React.TouchEvent<HTMLButtonElement>) => {
setIsDragging(true);
const touch = e.touches[0];
const rect = e.currentTarget.getBoundingClientRect();
setDragOffset({
x: touch.clientX - rect.left,
y: touch.clientY - rect.top
});
};
if (tasks.length === 0) {
return null;
}
return (
<div className='fixed bottom-6 right-6 z-[9998]'>
<div
style={{
position: 'fixed',
left: `${position.x}px`,
top: `${position.y}px`,
zIndex: 9998,
}}
>
<button
onClick={() => setShowDownloadPanel(true)}
onMouseDown={handleMouseDown}
onTouchStart={handleTouchStart}
onClick={(e) => {
if (!isDragging) {
setShowDownloadPanel(true);
}
}}
style={{
cursor: isDragging ? 'grabbing' : 'grab',
touchAction: 'none',
}}
className='relative group bg-gradient-to-r from-blue-500 to-purple-600 hover:from-blue-600 hover:to-purple-700 text-white rounded-full p-4 shadow-lg hover:shadow-xl transition-all duration-300 transform hover:scale-110'
>
{/* 下载图标 */}