DraggableButton.tsx 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
  1. import React, { useState, useImperativeHandle, forwardRef } from "react";
  2. // DraggableButton 组件
  3. const DraggableButton = forwardRef<HTMLDivElement, { children: React.ReactNode }>(({ children }, ref) => {
  4. let homePos = localStorage.getItem("homePos");
  5. let initPos = homePos ? JSON.parse(homePos) : { right: 200, top: 0 };
  6. const [position, setPosition] = useState(initPos);
  7. const [offset, setOffset] = useState({ x: 0, y: 0 });
  8. const handleDragStart = (e: React.DragEvent) => {
  9. const rect = e.currentTarget.getBoundingClientRect();
  10. setOffset({
  11. x: e.clientX - rect.left,
  12. y: e.clientY - rect.top
  13. });
  14. };
  15. const handleDrag = (e: React.DragEvent | any) => {
  16. if (e.clientX === 0 && e.clientY === 0) return; // 忽略拖动结束时的最后一个事件
  17. const newRight = window.innerWidth - (e.clientX - offset.x + e.currentTarget.offsetWidth);
  18. const newTop = e.clientY - offset.y;
  19. setPosition({ right: newRight, top: newTop });
  20. };
  21. const handleDragEnd = (e: React.DragEvent | any) => {
  22. const newRight = window.innerWidth - (e.clientX - offset.x + e.currentTarget.offsetWidth);
  23. const newTop = e.clientY - offset.y;
  24. setPosition({ right: newRight, top: newTop });
  25. localStorage.setItem("homePos", JSON.stringify({ right: newRight, top: newTop }));
  26. };
  27. // 使用 useImperativeHandle 将 DOM 节点暴露给父组件
  28. useImperativeHandle(ref, () => divRef.current!);
  29. const divRef = React.useRef<HTMLDivElement>(null);
  30. return (
  31. <div
  32. ref={divRef}
  33. draggable
  34. onDragStart={handleDragStart}
  35. onDrag={handleDrag}
  36. onDragEnd={handleDragEnd}
  37. style={{
  38. position: 'fixed',
  39. right: position.right,
  40. top: position.top,
  41. cursor: 'move',
  42. zIndex: 1000
  43. }}
  44. >
  45. {children}
  46. </div>
  47. );
  48. });
  49. export default DraggableButton;