index.tsx 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. import { ITouchEvent, View } from "@tarojs/components";
  2. import { RoundItem } from "../RoundItem";
  3. import Taro from "@tarojs/taro";
  4. import {
  5. forwardRef,
  6. useImperativeHandle,
  7. useMemo,
  8. useRef,
  9. useState,
  10. } from "react";
  11. import { useInterval } from "../../../../hooks/useInterval";
  12. import "./index.scss";
  13. import { SORT_MAP_ID } from "../../constants";
  14. export interface SwiperProps {
  15. curSwiperItem: number;
  16. handleDetail(id: number): void;
  17. setCurSwiperItem(num: number): void;
  18. }
  19. export interface SwiperMethods {
  20. toNext(): void;
  21. toPrev(): void;
  22. setIsRunning(v: boolean): void;
  23. }
  24. const SIGHT_COUNT = 26;
  25. const Big_R = (500 * Taro.getSystemInfoSync().windowWidth) / 750;
  26. const MIN_R = (150 * Taro.getSystemInfoSync().windowWidth) / 750;
  27. const getItemStack = () => {
  28. const stack: number[] = [];
  29. for (let i = 0; i <= 13; i++) {
  30. stack.push(i);
  31. }
  32. return stack;
  33. };
  34. export const Swiper = forwardRef<SwiperMethods, SwiperProps>(
  35. ({ curSwiperItem, setCurSwiperItem, handleDetail }, ref) => {
  36. const [itemStack, setItemStack] = useState(getItemStack());
  37. const touchStartX = useRef(0);
  38. const moving = useRef(false);
  39. const [isRunning, setIsRunning] = useState(false);
  40. const getNextItem = (curIndex: number, length: number) => {
  41. return (curIndex + 1) % length;
  42. };
  43. const getPreviousItem = (curIndex: number, length: number) => {
  44. return (curIndex - 1 + length) % length;
  45. };
  46. const getIndicesRelative = (curIndex: number, length: number) => {
  47. const nextIndex = getNextItem(curIndex, length);
  48. const nextThreeIndices = [nextIndex];
  49. for (let i = 1; i < 1; i++) {
  50. nextThreeIndices.push(getNextItem(nextThreeIndices[i - 1], length));
  51. }
  52. const previousIndex = getPreviousItem(curIndex, length);
  53. const previousThreeIndices = [previousIndex];
  54. for (let i = 1; i <= 2; i++) {
  55. previousThreeIndices.push(
  56. getPreviousItem(previousThreeIndices[i - 1], length)
  57. );
  58. }
  59. return [nextThreeIndices, previousThreeIndices];
  60. };
  61. const handleTouchStart = (e: ITouchEvent) => {
  62. setIsRunning(false);
  63. touchStartX.current = e.changedTouches[0].clientX;
  64. };
  65. const handleTouchEnd = (e: ITouchEvent) => {
  66. const touchEndX = e.changedTouches[0].clientX;
  67. const deltaX = touchEndX - touchStartX.current;
  68. if (deltaX > 50) {
  69. toPrev();
  70. } else if (deltaX < -50) {
  71. toNext();
  72. }
  73. };
  74. const toggleHandler = (fn: Function) => {
  75. if (moving.current) return;
  76. setIsRunning(false);
  77. moving.current = true;
  78. fn();
  79. };
  80. const toNext = () => {
  81. toggleHandler(() => {
  82. const temp = [...itemStack];
  83. const swiperItem = getNextItem(curSwiperItem, SIGHT_COUNT);
  84. temp.shift();
  85. temp.push(getNextItem(curSwiperItem + 3, SIGHT_COUNT));
  86. setItemStack(temp);
  87. setCurSwiperItem(swiperItem);
  88. });
  89. };
  90. const toPrev = () => {
  91. toggleHandler(() => {
  92. const temp = [...itemStack];
  93. const swiperItem = getPreviousItem(curSwiperItem, SIGHT_COUNT);
  94. temp.pop();
  95. temp.unshift(getPreviousItem(itemStack[0], SIGHT_COUNT));
  96. setItemStack(temp);
  97. setCurSwiperItem(swiperItem);
  98. });
  99. };
  100. const [nexts, prevs] = useMemo(
  101. () => getIndicesRelative(curSwiperItem, SIGHT_COUNT),
  102. [curSwiperItem]
  103. );
  104. const activeId = getPreviousItem(curSwiperItem, SIGHT_COUNT);
  105. const nearIds = [
  106. getPreviousItem(activeId, SIGHT_COUNT),
  107. getNextItem(activeId, SIGHT_COUNT),
  108. ];
  109. useImperativeHandle(ref, () => {
  110. return {
  111. toNext,
  112. toPrev,
  113. setIsRunning,
  114. };
  115. });
  116. useInterval(toNext, isRunning ? 5000 : null);
  117. return (
  118. <View
  119. className="sights"
  120. onTouchStart={handleTouchStart}
  121. onTouchEnd={handleTouchEnd}
  122. >
  123. {itemStack.map((id, idx) => {
  124. const realId = SORT_MAP_ID[id + 1 > 25 ? 0 : id + 1];
  125. const show =
  126. [...nexts, ...prevs].includes(id) || id === curSwiperItem;
  127. const isActive = activeId === id;
  128. return (
  129. show && (
  130. <RoundItem
  131. key={id}
  132. id={realId}
  133. angle={(360 / 12) * idx}
  134. bigR={Big_R}
  135. minR={MIN_R}
  136. isActive={isActive}
  137. isNear={nearIds.includes(id)}
  138. onClick={handleDetail.bind(undefined, realId)}
  139. onActLoaded={() => {
  140. setTimeout(() => {
  141. moving.current = false;
  142. setIsRunning(true);
  143. }, 500);
  144. }}
  145. />
  146. )
  147. );
  148. })}
  149. </View>
  150. );
  151. }
  152. );