下载按钮可拖动
This commit is contained in:
@@ -1,20 +1,131 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import React from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
|
|
||||||
import { useDownload } from '@/contexts/DownloadContext';
|
import { useDownload } from '@/contexts/DownloadContext';
|
||||||
|
|
||||||
export function DownloadBubble() {
|
export function DownloadBubble() {
|
||||||
const { tasks, downloadingCount, setShowDownloadPanel } = useDownload();
|
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) {
|
if (tasks.length === 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
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
|
<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'
|
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'
|
||||||
>
|
>
|
||||||
{/* 下载图标 */}
|
{/* 下载图标 */}
|
||||||
|
|||||||
Reference in New Issue
Block a user