Преглед на файлове

[stdf]Fix the error in the slider component where the slider cannot slide after clicking on it && Optimize sliding animation effect

mrlovables преди 2 години
родител
ревизия
1272ff3530
променени са 2 файла, в които са добавени 73 реда и са изтрити 7 реда
  1. 17 7
      packages/stdf/components/slider/Slider.svelte
  2. 56 0
      packages/stdf/components/utils/index.js

+ 17 - 7
packages/stdf/components/slider/Slider.svelte

@@ -1,7 +1,7 @@
 <script>
 	import { onMount, createEventDispatcher } from 'svelte';
 	import { fly } from 'svelte/transition';
-	import { throttle, stepNumberFun } from '../utils';
+	import { throttleWithRAF, debounce, stepNumberFun } from '../utils';
 
 	/**
 	 * 当前值
@@ -167,8 +167,11 @@
 		}
 	};
 	const touchLineMove = e => {
-		lineDom.setPointerCapture(e.pointerId);
-
+		if (!lineDom.hasPointerCapture(e.pointerId)) {
+			lineDom.setPointerCapture(1);
+		} else {
+			lineDom.setPointerCapture(e.pointerId);
+		}
 		if (disabled || readonly) {
 			return;
 		}
@@ -212,12 +215,14 @@
 			dispatch('change', value); //触发事件 trigger event
 		}
 	};
-	const touchLineEnd = () => {
+	const touchLineEnd = e => {
+		if (lineDom.hasPointerCapture(e.pointerId)) {
+			lineDom.releasePointerCapture(e.pointerId);
+		}
 		currentMove = 'none';
 		isDown = false;
 	};
-	const radiusObj = { none: ' rounded-none', base: ' rounded', xl: ' rounded-xl', full: ' rounded-full' };
-	onMount(() => {
+	const handleResize = () => {
 		lineDomStartX = lineDom.getBoundingClientRect().left;
 		lineDomEndX = lineDom.getBoundingClientRect().right;
 		lineDomWidth = lineDom.getBoundingClientRect().width;
@@ -227,13 +232,18 @@
 		if (isRange) {
 			blockWidth = blockDom.getBoundingClientRect().width;
 		}
+	};
+	const radiusObj = { none: ' rounded-none', base: ' rounded', xl: ' rounded-xl', full: ' rounded-full' };
+	onMount(() => {
+		handleResize();
+		window.addEventListener('resize', debounce(handleResize, 200));
 	});
 </script>
 
 <div class={`relative h-7${disabled ? ' opacity-50' : ''}`}>
 	<div
 		on:pointerdown={touchLineStart}
-		on:pointermove={throttle(touchLineMove)}
+		on:pointermove={throttleWithRAF(touchLineMove)}
 		on:pointerup={touchLineEnd}
 		class="absolute flex flex-col justify-center h-7 w-full touch-none cursor-move"
 		bind:this={lineDom}

+ 56 - 0
packages/stdf/components/utils/index.js

@@ -47,6 +47,62 @@ export const throttle = (fn, delay = 50) => {
 	};
 };
 
+/**
+ * 节流
+ * throttle With requestAnimationFrame
+ * @param {Function} fn
+ * @param {Number} delay
+ * @returns {Function}
+ */
+export const throttleWithRAF = (fn, delay = 16) => {
+	let timeoutId = null;
+	let rafId = null;
+	let lastExec = 0;
+	const throttledFn = function (...args) {
+		const now = performance.now();
+		const remainingTime = delay - (now - lastExec);
+		if (rafId === null && timeoutId === null) {
+			// 如果没有rafId和timeoutId,说明没有正在进行的动画帧或定时器
+			rafId = requestAnimationFrame(() => {
+				// 在动画帧开始时执行函数
+				fn.apply(this, args);
+				lastExec = performance.now();
+				rafId = null;
+			});
+		} else if (remainingTime <= 0) {
+			// 如果超过了延迟时间,取消当前的定时器,然后在下一个动画帧执行
+			clearTimeout(timeoutId);
+			timeoutId = null;
+			rafId = requestAnimationFrame(() => {
+				fn.apply(this, args);
+				lastExec = performance.now();
+				rafId = null;
+			});
+		} else {
+			// 如果还有剩余时间,设置定时器
+			clearTimeout(timeoutId);
+			timeoutId = setTimeout(() => {
+				rafId = requestAnimationFrame(() => {
+					fn.apply(this, args);
+					lastExec = performance.now();
+					rafId = null;
+				});
+			}, remainingTime);
+		}
+	};
+	throttledFn.clear = () => {
+		if (timeoutId !== null) {
+			clearTimeout(timeoutId);
+			timeoutId = null;
+		}
+		if (rafId !== null) {
+			cancelAnimationFrame(rafId);
+			rafId = null;
+		}
+	};
+	return throttledFn;
+};
+
 /**
  * 将数字按照步长进行四舍五入
  *  Round the number according to the step length