Slider.tsx 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. import React, { useRef, useState } from 'react';
  2. import './Slider.css';
  3. interface SliderProps {
  4. children: React.ReactNode;
  5. }
  6. function Slider({ children }: SliderProps) {
  7. const containerRef = useRef<HTMLDivElement>(null);
  8. const imageRef = useRef<HTMLDivElement>(null);
  9. const [isDragging, setIsDragging] = useState(false);
  10. const [startPosition, setStartPosition] = useState(0);
  11. const [currentTranslate, setCurrentTranslate] = useState(0);
  12. const [prevTranslate, setPrevTranslate] = useState(0);
  13. const [animationId, setAnimationId] = useState<number | null>(null);
  14. const [minTranslate, setMinTranslate] = useState(0);
  15. const [maxTranslate, setMaxTranslate] = useState(0);
  16. const startDragging = (event: any) => {
  17. if (event.type === 'touchstart') {
  18. setStartPosition(event.touches[0].clientX);
  19. } else {
  20. setStartPosition(event.clientX);
  21. }
  22. setIsDragging(true);
  23. cancelAnimationFrame(animationId!);
  24. };
  25. const dragging = (event: any) => {
  26. if (isDragging) {
  27. let currentPosition = 0;
  28. if (event.type === 'touchmove') {
  29. currentPosition = event.touches[0].clientX;
  30. } else {
  31. currentPosition = event.clientX;
  32. }
  33. const diff = currentPosition - startPosition;
  34. const newTranslate = prevTranslate + diff;
  35. const newMinTranslate = containerRef.current!.offsetWidth - imageRef.current!.offsetWidth;
  36. const newMaxTranslate = 0;
  37. if (newTranslate < newMinTranslate) {
  38. setCurrentTranslate(newMinTranslate);
  39. } else if (newTranslate > newMaxTranslate) {
  40. setCurrentTranslate(newMaxTranslate);
  41. } else {
  42. setCurrentTranslate(newTranslate);
  43. }
  44. }
  45. };
  46. const stopDragging = () => {
  47. setIsDragging(false);
  48. if (currentTranslate < minTranslate) {
  49. setCurrentTranslate(minTranslate);
  50. } else if (currentTranslate > maxTranslate) {
  51. setCurrentTranslate(maxTranslate);
  52. }
  53. setPrevTranslate(currentTranslate);
  54. setAnimationId(requestAnimationFrame(() => {
  55. imageRef.current!.style.transition = 'transform 0.3s ease-out';
  56. imageRef.current!.style.transform = `translateX(${currentTranslate}px)`;
  57. }));
  58. };
  59. const updateBoundaries = () => {
  60. if (containerRef.current && imageRef.current) {
  61. const containerWidth = containerRef.current.offsetWidth;
  62. const imageWidth = imageRef.current.offsetWidth;
  63. setMinTranslate(containerWidth - imageWidth);
  64. setMaxTranslate(0);
  65. }
  66. };
  67. return (
  68. <div
  69. className="slider-container"
  70. ref={containerRef}
  71. onMouseDown={startDragging}
  72. onTouchStart={startDragging}
  73. onMouseUp={stopDragging}
  74. onTouchEnd={stopDragging}
  75. onMouseLeave={stopDragging}
  76. onMouseMove={dragging}
  77. onTouchMove={dragging}
  78. onWheel={(event) => {
  79. event.preventDefault();
  80. setCurrentTranslate((prevTranslate) => {
  81. const scrollDistance = event.deltaY * -1;
  82. const maxScrollDistance = maxTranslate - prevTranslate;
  83. const minScrollDistance = minTranslate - prevTranslate;
  84. const scrollAmount =
  85. scrollDistance > 0
  86. ? Math.min(scrollDistance, maxScrollDistance)
  87. : Math.max(scrollDistance, minScrollDistance);
  88. return prevTranslate + scrollAmount;
  89. });
  90. }}
  91. onResize={updateBoundaries}
  92. >
  93. <div className="slider-con" ref={imageRef}>
  94. {children}
  95. </div>
  96. </div>
  97. );
  98. }
  99. export default Slider;