MoveOrderList.rn.tsx 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. import { MovableArea, MovableView, View, ScrollView, Text, Image } from '@tarojs/components'
  2. import './MoveOrderList.scss'
  3. import { useEffect, useRef, useState } from 'react';
  4. import { ColorType } from '@/context/themes/color';
  5. import Taro from '@tarojs/taro';
  6. import { IconDrag } from '@/components/basic/Icons';
  7. import { rpxToPx } from '@/utils/tools';
  8. export default function Component(props: { array: any, itemHeight: number, color?: string, update: Function }) {
  9. const [list, setList] = useState(props.array)
  10. const [movaleViewY, setMovaleViewY] = useState(0)
  11. const [dragElement, setDragElement] = useState(null)
  12. const [lastTarget, setLastTarget] = useState(null)
  13. const [startOffsetY, setStartOffsetY] = useState(0)
  14. const [startPageY, setStartPageY] = useState(0)
  15. const [dragIndex, setDragIndex] = useState(-1)
  16. const [scrollThreshold, setScrollThreshold] = useState(0.5)
  17. const upperThreshold = 100
  18. const lowThreshold = 100
  19. const [duration, setDuration] = useState(1000)
  20. const [canScroll, setCanScroll] = useState(true)
  21. const [changedIndex, setChangedIndex] = useState(-1)
  22. const [hiddenContent, setHiddenContent] = useState(false)
  23. const [scrollTop, setScrollTop] = useState(0)
  24. const [contentY, setContentY] = useState(0)
  25. const [contentHeight, setContentHeight] = useState(0)
  26. const ref = useRef(null)
  27. useEffect(() => {
  28. if (process.env.TARO_ENV == 'weapp') {
  29. const query = Taro.createSelectorQuery();
  30. query.select('#myScrollView').boundingClientRect();
  31. query.exec((res) => {
  32. setContentY(res[0].top)
  33. setContentHeight(res[0].height)
  34. })
  35. }
  36. else {
  37. }
  38. }, [])
  39. function touchStart(e, index) {
  40. setChangedIndex(index)
  41. setStartOffsetY(index*props.itemHeight)
  42. setStartPageY(e.touches[0].pageY)
  43. setDragIndex(index)
  44. setDragElement(list[index])
  45. setMovaleViewY(index*props.itemHeight)
  46. setCanScroll(false)
  47. }
  48. function longPress(e, index) {
  49. alert('long press')
  50. setChangedIndex(index)
  51. setStartOffsetY(e.target.offsetTop)
  52. setStartPageY(e.touches[0].pageY)
  53. setDragIndex(index)
  54. setDragElement(list[index])
  55. setMovaleViewY(e.target.offsetTop)
  56. setCanScroll(false)
  57. }
  58. function touchMove(e) {
  59. if (dragElement) {
  60. let clientY = e.nativeEvent.locationY;
  61. pageScroll(clientY);
  62. let pageY = e.nativeEvent.pageY;
  63. let targetMoveDistance = pageY - startPageY
  64. let movaleViewY2 = startOffsetY + targetMoveDistance
  65. let targetIndex = computeFutureIndex(targetMoveDistance, dragIndex)
  66. if (targetIndex !== false && targetIndex != changedIndex) {
  67. var temps = swapListItems(list, targetIndex, changedIndex)
  68. setList(temps)
  69. setChangedIndex(targetIndex)
  70. }
  71. if (targetIndex === false && targetIndex != changedIndex) {
  72. var temps = swapListItems(list, dragIndex, changedIndex)
  73. setList(temps)
  74. setChangedIndex(dragIndex)
  75. }
  76. setMovaleViewY(movaleViewY2)
  77. setLastTarget(targetIndex as any)
  78. setHiddenContent(true)
  79. }
  80. }
  81. function pageScroll(clientY) {
  82. return
  83. // console.log(clientY,contentY,contentHeight)
  84. if ((clientY - contentY) + upperThreshold >= contentHeight) {
  85. // var scroll = ref.current
  86. // debugger
  87. // (ref.current as any).scrollTo({scrollTop:100})
  88. // setScrollTop((clientY - contentY) + props.itemHeight)
  89. // setScrollTop(2200)
  90. // setCanScroll(true)
  91. Taro.pageScrollTo({
  92. selector: '#myScrollView',
  93. scrollTop: (clientY - contentY) + props.itemHeight,
  94. duration: 200
  95. })
  96. }
  97. else if ((clientY - contentY) - lowThreshold <= 0) {
  98. setScrollTop((clientY - contentY) - props.itemHeight)
  99. // setCanScroll(true)
  100. }
  101. else {
  102. // setCanScroll(true)
  103. }
  104. }
  105. function swapListItems<T>(list: T[], index1: number, index2: number): T[] {
  106. const newList = [...list];
  107. const temp = newList[index1];
  108. newList[index1] = newList[index2];
  109. newList[index2] = temp;
  110. return newList;
  111. }
  112. function touchEnd(e) {
  113. if (dragElement) {
  114. // let pageY = e.changedTouches[0].pageY
  115. // let targetMoveDistance = pageY - startPageY;
  116. // let dragElementIndex = dragIndex;
  117. // const futrueIndex = computeFutureIndex(targetMoveDistance, dragElementIndex)
  118. // if (futrueIndex !== false) {
  119. // var temps = list
  120. // temps.splice(futrueIndex, 0, temps.splice(dragIndex, 1)[0])
  121. // setList(temps)
  122. // }
  123. setDragElement(null)
  124. setLastTarget(null)
  125. setDragIndex(-1)
  126. }
  127. setChangedIndex(-1)
  128. setCanScroll(true)
  129. setHiddenContent(false)
  130. setMovaleViewY(-100)
  131. props.update(list)
  132. }
  133. function computeFutureIndex(targetMoveDistance, dragElementIndex) {
  134. let willInsertAfter = getSwapDirection(targetMoveDistance);
  135. if (willInsertAfter !== false) {
  136. /** 偏移索引 */
  137. let offsetElementIndex = dragElementIndex + willInsertAfter;
  138. /** 移动步数 */
  139. let step = targetMoveDistance / props.itemHeight;
  140. /** 步数补偿,当只有移动距离超过单项 _scrollThreshold 时才算有效 */
  141. if (step <= -1) {
  142. step += scrollThreshold;
  143. } else if (step >= 1) {
  144. step -= scrollThreshold;
  145. }
  146. /** 目标索引 */
  147. let futureIndex = parseInt(step) + offsetElementIndex;
  148. // 避免越界
  149. if (futureIndex < 0) {
  150. futureIndex = 0;
  151. } else if (futureIndex > list.length - 1) {
  152. futureIndex = list.length - 1;
  153. }
  154. return futureIndex;
  155. } else {
  156. return willInsertAfter;
  157. }
  158. }
  159. function getSwapDirection(targetMoveDistance) {
  160. if (Math.abs(targetMoveDistance) < props.itemHeight / 2) {
  161. // 轻轻拂动,滑动距离小于1/2单项高度
  162. return false;
  163. } else if (targetMoveDistance >= props.itemHeight / 2) {
  164. // console.log('[_getSwapDirection] 👇👇👇');
  165. return 1; // 下滑
  166. } else if (targetMoveDistance <= props.itemHeight / -2) {
  167. // console.log('[_getSwapDirection] 👆👆👆');
  168. return -1; // 上滑
  169. }
  170. }
  171. return <View id="myScrollView" ref={ref} style={{ height: '100%', overflow: canScroll ? 'scroll' : 'hidden' }} catchMove>
  172. <MovableArea style={{ height: list.length * props.itemHeight, width: rpxToPx(750) }}>
  173. <View>
  174. {
  175. list.map((item, index) => {
  176. return <View key={index} style={{ opacity: changedIndex == index && hiddenContent ? 0 : 1, height: props.itemHeight, width: rpxToPx(750) }}
  177. // onLongPress={(e) => longPress(e, index)}
  178. onTouchStart={(e) => touchStart(e, index)}
  179. onTouchMove={(e) => touchMove(e)}
  180. onTouchEnd={(e) => touchEnd(e)}
  181. >
  182. <View className='modal_order_item' style={{ height: 40, flexDirection: 'column' }}>
  183. <View style={{
  184. height: 40,
  185. display: 'flex', flexDirection: 'row',
  186. width: '100%',
  187. alignItems: 'center', justifyContent: 'space-between'
  188. }}>
  189. <Text style={{ color: props.color, fontSize: rpxToPx(32) }}>{item.name}</Text>
  190. <IconDrag width={17} height={12} />
  191. </View>
  192. <View className='seperate' />
  193. </View>
  194. </View>
  195. })
  196. }
  197. <View style={{position:'absolute',left:0,width:rpxToPx(750),top:movaleViewY,height: changedIndex >= 0 ? props.itemHeight : 0}}>
  198. <View className='drag_item' style={{ backgroundColor: props.color }}>
  199. {
  200. dragIndex >= 0 && <View className='modal_sel_item' style={{ height: 40, border: 'none' }}>
  201. <Text style={{ color: 'black', fontWeight: 'bold' }}>{list[changedIndex].name}</Text>
  202. <IconDrag width={17} height={12} />
  203. </View>
  204. }
  205. </View>
  206. </View>
  207. {/* <MovableView style={{ height: changedIndex >= 0 ? props.itemHeight : 0, width: rpxToPx(750),backgroundColor:'red' }}
  208. direction='vertical'
  209. disabled
  210. animation={true}
  211. y={movaleViewY}
  212. >
  213. <View className='drag_item' style={{ backgroundColor: props.color }}>
  214. {
  215. dragIndex >= 0 && <View className='modal_sel_item' style={{ height: 40, border: 'none' }}>
  216. <Text style={{ color: 'black', fontWeight: 'bold' }}>{list[changedIndex].name}</Text>
  217. <IconDrag width={17} height={12} />
  218. </View>
  219. }
  220. </View>
  221. </MovableView> */}
  222. </View>
  223. </MovableArea>
  224. </View>
  225. }