86 lines
		
	
	
		
			2.1 KiB
		
	
	
	
		
			TypeScript
		
	
	
			
		
		
	
	
			86 lines
		
	
	
		
			2.1 KiB
		
	
	
	
		
			TypeScript
		
	
	
| import type { Ref } from 'vue';
 | |
| import { onBeforeUnmount, watch, onMounted } from 'vue';
 | |
| 
 | |
| const SMOOTH_PTG = 14 / 15;
 | |
| export default function useMobileTouchMove(
 | |
|   inVirtual: Ref<boolean>,
 | |
|   listRef: Ref<HTMLDivElement | undefined>,
 | |
|   callback: (offsetY: number, smoothOffset?: boolean) => boolean,
 | |
| ) {
 | |
|   let touched = false;
 | |
|   let touchY = 0;
 | |
| 
 | |
|   let element: HTMLElement | null = null;
 | |
| 
 | |
|   // Smooth scroll
 | |
|   let interval: any = null;
 | |
| 
 | |
|   const cleanUpEvents = () => {
 | |
|     if (element) {
 | |
|       element.removeEventListener('touchmove', onTouchMove);
 | |
|       element.removeEventListener('touchend', onTouchEnd);
 | |
|     }
 | |
|   };
 | |
| 
 | |
|   const onTouchMove = (e: TouchEvent) => {
 | |
|     if (touched) {
 | |
|       const currentY = Math.ceil(e.touches[0].pageY);
 | |
|       let offsetY = touchY - currentY;
 | |
|       touchY = currentY;
 | |
| 
 | |
|       if (callback(offsetY)) {
 | |
|         e.preventDefault();
 | |
|       }
 | |
| 
 | |
|       // Smooth interval
 | |
|       clearInterval(interval);
 | |
|       interval = setInterval(() => {
 | |
|         offsetY *= SMOOTH_PTG;
 | |
| 
 | |
|         if (!callback(offsetY, true) || Math.abs(offsetY) <= 0.1) {
 | |
|           clearInterval(interval);
 | |
|         }
 | |
|       }, 16);
 | |
|     }
 | |
|   };
 | |
| 
 | |
|   const onTouchEnd = () => {
 | |
|     touched = false;
 | |
| 
 | |
|     cleanUpEvents();
 | |
|   };
 | |
| 
 | |
|   const onTouchStart = (e: TouchEvent) => {
 | |
|     cleanUpEvents();
 | |
| 
 | |
|     if (e.touches.length === 1 && !touched) {
 | |
|       touched = true;
 | |
|       touchY = Math.ceil(e.touches[0].pageY);
 | |
| 
 | |
|       element = e.target as HTMLElement;
 | |
|       element!.addEventListener('touchmove', onTouchMove, { passive: false });
 | |
|       element!.addEventListener('touchend', onTouchEnd);
 | |
|     }
 | |
|   };
 | |
|   const noop = () => {};
 | |
| 
 | |
|   onMounted(() => {
 | |
|     document.addEventListener('touchmove', noop, { passive: false });
 | |
|     watch(
 | |
|       inVirtual,
 | |
|       val => {
 | |
|         listRef.value.removeEventListener('touchstart', onTouchStart);
 | |
|         cleanUpEvents();
 | |
|         clearInterval(interval);
 | |
|         if (val) {
 | |
|           listRef.value.addEventListener('touchstart', onTouchStart, { passive: false });
 | |
|         }
 | |
|       },
 | |
|       { immediate: true },
 | |
|     );
 | |
|   });
 | |
|   onBeforeUnmount(() => {
 | |
|     document.removeEventListener('touchmove', noop);
 | |
|   });
 | |
| }
 |