瀏覽代碼

Modify the touch events in the components to pointer events

杜府 3 年之前
父節點
當前提交
7b91167a68

+ 2 - 2
components/package.json

@@ -1,7 +1,7 @@
 {
     "name": "stdf",
-    "version": "0.1.4",
-    "description": "Mobile Web component library based on Svelte and Tailwind",
+    "version": "0.1.5",
+    "description": "Mobile web component library based on Svelte and Tailwind",
     "main": "index.js",
     "scripts": {
         "test": "echo \"Error: no test specified\" && exit 1"

+ 13 - 4
components/src/bottomSheet/BottomSheet.svelte

@@ -1,6 +1,7 @@
 <script>
     import { onMount, createEventDispatcher, getContext } from 'svelte';
     import { fly } from 'svelte/transition';
+    import { debounce } from '../utils';
     import zh_CN from '../../lang/zh_CN';
 
     import Mask from '../mask/Mask.svelte';
@@ -174,14 +175,16 @@
     const touchstartFun = e => {
         moveDistance = 0;
         startTop = currentTop;
-        startY = e.touches[0].clientY;
+        startY = e.clientY;
         isTouch = true;
     };
 
     // 滑动中
     // sliding
     const touchmoveFun = e => {
-        currentY = e.touches[0].clientY;
+        if (!isTouch) return;
+        scrollTopDom.setPointerCapture(e.pointerId);
+        currentY = e.clientY;
         //移动百分比,moveDistance为正时,向下移动
         //Move percentage, moveDistance is positive when moving down
         moveDistance = ((currentY - startY) / window.innerHeight) * 100;
@@ -293,7 +296,13 @@
             in:fly={{ y: (stayHeightList[stayHeightList.length - 1] / 100) * window.innerHeight, opacity: 1, duration }}
             out:fly={{ y: (stayHeightList[stayHeightList.length - 1] / 100) * window.innerHeight, opacity: 1, duration: outDuration }}
         >
-            <div class="py-1" bind:this={scrollTopDom} on:touchstart={touchstartFun} on:touchmove={touchmoveFun} on:touchend={touchendFun}>
+            <div
+                on:pointerdown={touchstartFun}
+                on:pointermove={debounce(touchmoveFun, 5)}
+                on:pointerup={touchendFun}
+                bind:this={scrollTopDom}
+                class="py-1 touch-none cursor-move select-none"
+            >
                 <div class={`w-8 h-1 bg-black/20 dark:bg-white/30 mx-auto${radius === 'none' ? ' rounded-none' : ' rounded-full'}`} />
                 <div class="px-3 py-1 flex justify-between items-center gap-2">
                     {#if showBackIcon}
@@ -334,7 +343,7 @@
                         </div>
                     {:else}
                         <!-- svelte-ignore a11y-click-events-have-key-events -->
-                        <div class="text-primary dark:text-dark font-bold" on:click={closeFunc}>{closeContent}</div>
+                        <div class="text-primary dark:text-dark font-bold cursor-pointer" on:click={closeFunc}>{closeContent}</div>
                     {/if}
                 </div>
             </div>

+ 27 - 38
components/src/indexBar/IndexBar.svelte

@@ -59,6 +59,12 @@
     // Bar outside the distance from the top
     let barToTop = 0;
 
+    // bar元素
+    // bar element
+    let barDom = null;
+
+    let isDown = false; //是否按下 is down
+
     // 每一个的高度
     // Height of each
     $: itemHeight = barHeight / data.length;
@@ -90,8 +96,10 @@
     //bar区域滑动开始
     //Bar area sliding start
     const touchBoxStart = e => {
-        currentTouch = Math.floor((e.targetTouches[0].clientY - barToTop) / itemHeight);
-        current = Math.floor((e.targetTouches[0].clientY - barToTop) / itemHeight);
+        isDown = true;
+        const clientY = e.clientY;
+        currentTouch = Math.floor((clientY - barToTop) / itemHeight);
+        current = Math.floor((clientY - barToTop) / itemHeight);
         bodyDom.scrollTop = data.slice(0, current).reduce((sum, current) => {
             return sum + current.height;
         }, 0);
@@ -100,13 +108,18 @@
     // bar区域滑动中
     // bar area sliding in the middle
     const touchBoxMove = e => {
-        currentTouch = Math.floor((e.targetTouches[0].clientY - barToTop) / itemHeight);
-        current = Math.floor((e.targetTouches[0].clientY - barToTop) / itemHeight);
-        if (e.targetTouches[0].clientY < barToTop) {
+        if (!isDown) {
+            return;
+        }
+        barDom.setPointerCapture(e.pointerId);
+        const clientY = e.clientY;
+        currentTouch = Math.floor((clientY - barToTop) / itemHeight);
+        current = Math.floor((clientY - barToTop) / itemHeight);
+        if (clientY < barToTop) {
             currentTouch = 0;
             current = 0;
         }
-        if (e.targetTouches[0].clientY > barHeight + barToTop) {
+        if (clientY > barHeight + barToTop) {
             currentTouch = data.length - 1;
             current = data.length - 1;
         }
@@ -119,6 +132,7 @@
     // bar area sliding end
     const touchBoxEnd = () => {
         currentTouch = -1;
+        isDown = false;
     };
 
     //监听主体内容滚动
@@ -139,34 +153,6 @@
         // Dispatch click events to pass four parameters out. 1. index: the parent group index value of the clicked item; 2. group: the parent group content of the clicked item; 3. childIndex: the index value of the clicked item; 4. child: the content of the clicked item.
         dispatch('clickchild', { index, group, childIndex, child });
     };
-    //防抖
-    // function debounce(fn, delay) {
-    //     let timer = null;
-    //     return function () {
-    //         if (timer) {
-    //             clearTimeout(timer);
-    //         }
-    //         timer = setTimeout(() => {
-    //             //模拟触发change事件
-    //             fn.apply(this, arguments);
-    //             // 清空计时器
-    //             timer = null;
-    //         }, delay);
-    //     };
-    // }
-    // 节流
-    // const throttle = (fn, delay = 50) => {
-    //     let timer = null;
-    //     return function () {
-    //         if (timer) {
-    //             return;
-    //         }
-    //         timer = setTimeout(() => {
-    //             fn.apply(this, arguments);
-    //             timer = null;
-    //         }, delay);
-    //     };
-    // };
 </script>
 
 <div bind:this={bodyDom} class={`overflow-y-auto ${scrollAlign && 'snap-y'}`} on:scroll={scrollBody} style="height:{height}px;">
@@ -184,11 +170,14 @@
     {/each}
 </div>
 <div
-    on:touchstart={touchBoxStart}
-    on:touchmove|preventDefault={debounce(touchBoxMove)}
-    on:touchend={debounce(touchBoxEnd, 15)}
+    on:pointerdown={touchBoxStart}
+    on:pointermove={debounce(touchBoxMove, 5)}
+    on:pointerup={debounce(touchBoxEnd, 15)}
     bind:clientHeight={barHeight}
-    class={`fixed right-5 bg-black/5 dark:bg-white/5 w-7 p-1 flex flex-col justify-around ${radiusObj[radius] || radiusObj.base}`}
+    bind:this={barDom}
+    class={`fixed right-5 bg-black/5 dark:bg-white/5 w-7 p-1 flex flex-col justify-around touch-none cursor-move select-none ${
+        radiusObj[radius] || radiusObj.base
+    }`}
     style="top:{top + (height - barHeight) / 2}px;min-height:{height / 4}px;"
 >
     {#each data as group, i}

+ 2 - 1
components/src/scrollRadio/ScrollRadio.svelte

@@ -110,9 +110,10 @@
         class={`overflow-auto snap-y picker-contents ${useAnimation ? 'scroll-smooth' : 'scroll-auto'}`}
         style="height:{itemHeight * showRowsInner}rem;"
         bind:this={scrollElement}
-        on:touchstart={() => {
+        on:scroll={() => {
             isTouch = true;
         }}
+        
     >
         {#each newData as item}
             <div

+ 167 - 101
components/src/slider/Slider.svelte

@@ -1,153 +1,167 @@
 <script>
-    import {onMount, createEventDispatcher} from 'svelte';
-    import {fly} from 'svelte/transition';
-    import {debounce, stepNumberFun} from '../utils';
+    import { onMount, createEventDispatcher } from 'svelte';
+    import { fly } from 'svelte/transition';
+    import { debounce, stepNumberFun } from '../utils';
 
     // 当前值
     // Current value
-    export let value = 40; 
+    export let value = 40;
 
     // 步长
     // Step length
-    export let step = 1; 
-    
+    export let step = 1;
+
     // 可选最小值
     // Optional minimum value
-    export let minRange = 0; 
-    
+    export let minRange = 0;
+
     // 可选最大值
     // Optional maximum value
-    export let maxRange = 100; 
-    
+    export let maxRange = 100;
+
     // 是否为区间选择
     // is range
-    export let isRange = false; 
-    
+    export let isRange = false;
+
     // 区间选择开始值
     // Range selection start value
-    export let startValue = 20; 
-    
+    export let startValue = 20;
+
     // 区间选择结束值
     // Range selection end value
-    export let endValue = 60; 
-    
+    export let endValue = 60;
+
     // 提示显示方式
     // Tip display method
-    export let showTip = 'touch'; 
+    export let showTip = 'touch';
 
     // 圆角
     // radius
-    export let radius = 'full'; 
-    
+    export let radius = 'full';
+
     // 滑块是否为线框
     // is line block
-    export let lineBlock = false; 
+    export let lineBlock = false;
 
     // 是否使用slot
     // is use slot
-    export let useSlot = false; 
-    
+    export let useSlot = false;
+
     // 是否禁用
     // is disabled
-    export let disabled = false; 
-    
+    export let disabled = false;
+
     // 是否只读
     // is readonly
-    export let readonly = false; 
-    
-    
-    let lineDom = null;//滑动条dom
-    let blockDom = null;//滑块dom
-    let blockWidth = 0;//滑块宽度
-    let lineDomStartX = 0;//滑块条起始位置
-    let lineDomEndX = 0;//滑块条结束位置
-    let lineDomWidth = 0;//滑块条宽度
-    let currentX = (value - minRange) / (maxRange - minRange) * lineDomWidth; //初始位置
-    let currentStartX = (startValue - minRange) / (maxRange - minRange) * lineDomWidth; //区间选择时开始位置
-    let currentEndX = (endValue - minRange) / (maxRange - minRange) * lineDomWidth; //区间选择时结束位置
-    let currentMove = 'none';//当前移动的滑块
-    const dispatch = createEventDispatcher();//事件分发器
+    export let readonly = false;
+
+    let lineDom = null; //滑动条dom slider dom
+    let blockDom = null; //滑块dom block dom
+    let blockWidth = 0; //滑块宽度 block width
+    let lineDomStartX = 0; //滑块条起始位置 slider start position
+    let lineDomEndX = 0; //滑块条结束位置 slider end position
+    let lineDomWidth = 0; //滑块条宽度 slider width
+    let currentX = ((value - minRange) / (maxRange - minRange)) * lineDomWidth; //初始位置 initial position
+    let currentStartX = ((startValue - minRange) / (maxRange - minRange)) * lineDomWidth; //区间选择时开始位置 start position
+    let currentEndX = ((endValue - minRange) / (maxRange - minRange)) * lineDomWidth; //区间选择时结束位置 end position
+    let currentMove = 'none'; //当前移动的滑块 current move block
+
+    let isDown = false; //是否按下 is down
+    const dispatch = createEventDispatcher(); //事件分发器 event dispatcher
+
     //滑动开始
+    //slide start
     const touchLineStart = e => {
         if (disabled || readonly) {
             return;
         }
+        isDown = true;
+        const clientX = e.clientX;
         if (isRange) {
             //判断点击位置距离哪一个更近
+            // Determine which one is closer to the click position
             if (startValue === endValue) {
-                console.log(e.targetTouches[0].clientX, currentStartX, currentEndX);
-                if (e.targetTouches[0].clientX - lineDomStartX <= currentStartX) {
+                if (clientX - lineDomStartX <= currentStartX) {
                     // 点击的是开始滑块
+                    // Click on the start block
                     currentMove = 'start';
-                    currentStartX = e.targetTouches[0].clientX - lineDomStartX;
+                    currentStartX = clientX - lineDomStartX;
                 } else {
                     // 点击的是结束滑块
+                    // Click on the end block
                     currentMove = 'end';
-                    console.log('点击的是结束滑块1');
-                    currentEndX = e.targetTouches[0].clientX - lineDomStartX;
+                    currentEndX = clientX - lineDomStartX;
                 }
-            } else if (Math.abs(e.targetTouches[0].clientX - currentStartX - lineDomStartX) <
-                Math.abs(e.targetTouches[0].clientX - currentEndX - lineDomStartX)) {
+            } else if (Math.abs(clientX - currentStartX - lineDomStartX) < Math.abs(clientX - currentEndX - lineDomStartX)) {
                 // 点击的是开始滑块
+                // Click on the start block
                 currentMove = 'start';
-                currentStartX = e.targetTouches[0].clientX - lineDomStartX;
+                currentStartX = clientX - lineDomStartX;
             } else {
-                console.log('点击的是结束滑块2');
                 // 点击的是结束滑块
+                // Click on the end block
                 currentMove = 'end';
-                currentEndX = e.targetTouches[0].clientX - lineDomStartX;
+                currentEndX = clientX - lineDomStartX;
             }
-            startValue = stepNumberFun(minRange + currentStartX / lineDomWidth * (maxRange - minRange), step);
-            endValue = stepNumberFun(minRange + currentEndX / lineDomWidth * (maxRange - minRange), step);
-            dispatch('change', [startValue, endValue]);//触发事件
+            startValue = stepNumberFun(minRange + (currentStartX / lineDomWidth) * (maxRange - minRange), step);
+            endValue = stepNumberFun(minRange + (currentEndX / lineDomWidth) * (maxRange - minRange), step);
+            dispatch('change', [startValue, endValue]); //触发事件 trigger event
         } else {
             currentMove = 'one';
-            currentX = e.targetTouches[0].clientX - lineDomStartX;
-            value = stepNumberFun(currentX / lineDomWidth * (maxRange - minRange), step);
-            dispatch('change', value);//触发事件
+            currentX = clientX - lineDomStartX;
+            value = stepNumberFun((currentX / lineDomWidth) * (maxRange - minRange), step);
+            dispatch('change', value); //触发事件 trigger event
         }
     };
     const touchLineMove = e => {
+        lineDom.setPointerCapture(e.pointerId);
+
         if (disabled || readonly) {
             return;
         }
+        if (!isDown) {
+            return;
+        }
+        const clientX = e.clientX;
         if (isRange) {
             if (currentMove === 'start') {
-                if (e.targetTouches[0].clientX <= lineDomStartX) {
+                if (clientX <= lineDomStartX) {
                     currentStartX = 0;
-                } else if (e.targetTouches[0].clientX >= currentEndX + blockWidth / 2) {
+                } else if (clientX >= currentEndX + blockWidth / 2) {
                     currentStartX = currentEndX;
                 } else {
-                    currentStartX = e.targetTouches[0].clientX - lineDomStartX;
+                    currentStartX = clientX - lineDomStartX;
                 }
             } else {
-                if (e.targetTouches[0].clientX <= currentStartX + blockWidth / 2) {
+                if (clientX <= currentStartX + blockWidth / 2) {
                     currentEndX = currentStartX;
-                } else if (e.targetTouches[0].clientX >= lineDomEndX) {
+                } else if (clientX >= lineDomEndX) {
                     currentEndX = lineDomEndX - lineDomStartX;
                 } else {
-                    currentEndX = e.targetTouches[0].clientX - lineDomStartX;
+                    currentEndX = clientX - lineDomStartX;
                     //由于开启了防抖,有极短时间内会出现currentEndX大于lineDomEndX的情况,所以这里做了一个判断
+                    //Due to the opening of the anti-shake, there will be a situation where currentEndX is greater than lineDomEndX in a very short time, so a judgment is made here
                     currentEndX = currentEndX < currentStartX ? currentStartX : currentEndX;
                 }
             }
-            startValue = stepNumberFun(minRange + currentStartX / lineDomWidth * (maxRange - minRange), step);
-            endValue = stepNumberFun(minRange + currentEndX / lineDomWidth * (maxRange - minRange), step);
-            dispatch('change', [startValue, endValue]);//触发事件
+            startValue = stepNumberFun(minRange + (currentStartX / lineDomWidth) * (maxRange - minRange), step);
+            endValue = stepNumberFun(minRange + (currentEndX / lineDomWidth) * (maxRange - minRange), step);
+            dispatch('change', [startValue, endValue]); //触发事件 trigger event
         } else {
-            if (e.targetTouches[0].clientX <= lineDomStartX) {
+            if (clientX <= lineDomStartX) {
                 currentX = 0;
-            } else if (e.targetTouches[0].clientX >= lineDomEndX) {
+            } else if (clientX >= lineDomEndX) {
                 currentX = lineDomEndX - lineDomStartX;
             } else {
-                currentX = e.targetTouches[0].clientX - lineDomStartX;
+                currentX = clientX - lineDomStartX;
             }
-            value = stepNumberFun(minRange + currentX / lineDomWidth * (maxRange - minRange), step);
-            dispatch('change', value);//触发事件
+            value = stepNumberFun(minRange + (currentX / lineDomWidth) * (maxRange - minRange), step);
+            dispatch('change', value); //触发事件 trigger event
         }
     };
-    const touchLineEnd = () => {
+    const touchLineEnd = e => {
         currentMove = 'none';
+        isDown = false;
     };
     const radiusObj = {
         none: ' rounded-none',
@@ -159,70 +173,122 @@
         lineDomStartX = lineDom.getBoundingClientRect().left;
         lineDomEndX = lineDom.getBoundingClientRect().right;
         lineDomWidth = lineDom.getBoundingClientRect().width;
-        currentX = (value - minRange) / (maxRange - minRange) * lineDomWidth; //挂载完成之后初始位置
-        currentStartX = (startValue - minRange) / (maxRange - minRange) * lineDomWidth; //区间选择开始位置
-        currentEndX = (endValue - minRange) / (maxRange - minRange) * lineDomWidth; //区间选择结束位置
+        currentX = ((value - minRange) / (maxRange - minRange)) * lineDomWidth; //挂载完成之后初始位置 initial position after mounting
+        currentStartX = ((startValue - minRange) / (maxRange - minRange)) * lineDomWidth; //区间选择开始位置 initial position after mounting
+        currentEndX = ((endValue - minRange) / (maxRange - minRange)) * lineDomWidth; //区间选择结束位置 initial position after mounting
         if (isRange) {
             blockWidth = blockDom.getBoundingClientRect().width;
         }
     });
 </script>
+
 <div class={`relative h-7${disabled ? ' opacity-50' : ''}`}>
-    <div on:touchstart={touchLineStart} on:touchmove|preventDefault={debounce(touchLineMove,15)} on:touchend={touchLineEnd}
-         class="absolute flex flex-col justify-center h-7 w-full" bind:this={lineDom}>
+    <!-- svelte-ignore a11y-mouse-events-have-key-events -->
+    <div
+        on:pointerdown={touchLineStart}
+        on:pointermove={debounce(touchLineMove, 5)}
+        on:pointerup={touchLineEnd}
+        class="absolute flex flex-col justify-center h-7 w-full touch-none cursor-move"
+        bind:this={lineDom}
+    >
         {#if useSlot}
-            <slot></slot>
+            <slot />
         {:else}
-            <div class={`w-full h-1 bg-black/5 dark:bg-white/5${radiusObj[radius]||radiusObj['full']}`}>
+            <div class={`w-full h-1 bg-black/5 dark:bg-white/5${radiusObj[radius] || radiusObj['full']}`}>
                 {#if isRange}
-                    <div class={`bg-primary dark:bg-dark h-1${radiusObj[radius]||radiusObj['full']}`}
-                         style={`width:${currentEndX-currentStartX}px;transform: translateX(${currentStartX}px);`}></div>
+                    <div
+                        class={`bg-primary dark:bg-dark h-1${radiusObj[radius] || radiusObj['full']}`}
+                        style={`width:${currentEndX - currentStartX}px;transform: translateX(${currentStartX}px);`}
+                    />
                 {:else}
-                    <div class={`bg-primary dark:bg-dark h-1${radiusObj[radius]||radiusObj['full']}`} style={`width:${currentX}px`}></div>
+                    <div class={`bg-primary dark:bg-dark h-1${radiusObj[radius] || radiusObj['full']}`} style={`width:${currentX}px`} />
                 {/if}
             </div>
         {/if}
     </div>
     {#if isRange}
         <div class="absolute flex flex-col justify-center h-7 w-full pointer-events-none">
-            <div class={`${lineBlock?'w-6 h-6 border border-primary dark:border-dark bg-white dark:bg-gray2':'w-5 h-5 ring-4 ring-primary/10 dark:ring-dark/10 bg-primary dark:bg-dark'}${radiusObj[radius]||radiusObj['full']}`}
-                 style={`transform: translateX(calc(${currentStartX}px - 50%));`}>
-                {#if showTip === 'always' || currentMove === 'start' && showTip !== 'never'}
-                    <div class={`absolute -top-9 text-white dark:text-black text-xs py-1 bg-black/90 dark:bg-white px-2${radius==='none'?' rounded-none':' rounded'}`}
-                         style={`left: 50%;transform: translateX(-50%);`} in:fly={{ y: 8, duration: 500 }} out:fly={{ y: 8, duration: 300 }}>
+            <div
+                class={`${
+                    lineBlock
+                        ? 'w-6 h-6 border border-primary dark:border-dark bg-white dark:bg-gray2'
+                        : 'w-5 h-5 ring-4 ring-primary/10 dark:ring-dark/10 bg-primary dark:bg-dark'
+                }${radiusObj[radius] || radiusObj['full']}`}
+                style={`transform: translateX(calc(${currentStartX}px - 50%));`}
+            >
+                {#if showTip === 'always' || (currentMove === 'start' && showTip !== 'never')}
+                    <div
+                        class={`absolute -top-9 text-white dark:text-black text-xs py-1 bg-black/90 dark:bg-white px-2${
+                            radius === 'none' ? ' rounded-none' : ' rounded'
+                        }`}
+                        style={`left: 50%;transform: translateX(-50%);`}
+                        in:fly={{ y: 8, duration: 500 }}
+                        out:fly={{ y: 8, duration: 300 }}
+                    >
                         {startValue}
-                        <div class="absolute w-0 h-0 border-4 border-t-4 border-transparent border-t-black/90 dark:border-t-white"
-                             style={`top:100%;left:50%;transform: translateX(-50%)`}></div>
+                        <div
+                            class="absolute w-0 h-0 border-4 border-t-4 border-transparent border-t-black/90 dark:border-t-white"
+                            style={`top:100%;left:50%;transform: translateX(-50%)`}
+                        />
                     </div>
                 {/if}
             </div>
         </div>
         <div class="absolute flex flex-col justify-center h-7 w-full pointer-events-none">
-            <div class={`${lineBlock?'w-6 h-6 border border-primary dark:border-dark bg-white dark:bg-gray2':'w-5 h-5 ring-4 ring-primary/10 dark:ring-dark/10 bg-primary dark:bg-dark'}${radiusObj[radius]||radiusObj['full']}`}
-                 style={`transform: translateX(calc(${currentEndX}px - 50%));`} bind:this={blockDom}>
-                {#if showTip === 'always' || currentMove === 'end' && showTip !== 'never'}
-                    <div class={`absolute -top-9 text-white dark:text-black text-xs py-1 bg-black/90 dark:bg-white px-2${radius==='none'?' rounded-none':' rounded'}`}
-                         style={`left: 50%;transform: translateX(-50%);`} in:fly={{ y: 8, duration: 500 }} out:fly={{ y: 8, duration: 300 }}>
+            <div
+                class={`${
+                    lineBlock
+                        ? 'w-6 h-6 border border-primary dark:border-dark bg-white dark:bg-gray2'
+                        : 'w-5 h-5 ring-4 ring-primary/10 dark:ring-dark/10 bg-primary dark:bg-dark'
+                }${radiusObj[radius] || radiusObj['full']}`}
+                style={`transform: translateX(calc(${currentEndX}px - 50%));`}
+                bind:this={blockDom}
+            >
+                {#if showTip === 'always' || (currentMove === 'end' && showTip !== 'never')}
+                    <div
+                        class={`absolute -top-9 text-white dark:text-black text-xs py-1 bg-black/90 dark:bg-white px-2${
+                            radius === 'none' ? ' rounded-none' : ' rounded'
+                        }`}
+                        style={`left: 50%;transform: translateX(-50%);`}
+                        in:fly={{ y: 8, duration: 500 }}
+                        out:fly={{ y: 8, duration: 300 }}
+                    >
                         {endValue}
-                        <div class="absolute w-0 h-0 border-4 border-t-4 border-transparent border-t-black/90 dark:border-t-white"
-                             style={`top:100%;left:50%;transform: translateX(-50%)`}></div>
+                        <div
+                            class="absolute w-0 h-0 border-4 border-t-4 border-transparent border-t-black/90 dark:border-t-white"
+                            style={`top:100%;left:50%;transform: translateX(-50%)`}
+                        />
                     </div>
                 {/if}
             </div>
         </div>
     {:else}
         <div class="absolute flex flex-col justify-center h-7 w-full pointer-events-none">
-            <div class={`${lineBlock?'w-6 h-6 border border-primary dark:border-dark bg-white dark:bg-gray2':'w-5 h-5 ring-4 ring-primary/10 dark:ring-dark/10 bg-primary dark:bg-dark'}${radiusObj[radius]||radiusObj['full']}`}
-                 style={`transform: translateX(calc(${currentX}px - 50%));`}>
-                {#if showTip === 'always' || currentMove === 'one' && showTip !== 'never'}
-                    <div class={`absolute -top-9 text-white dark:text-black text-xs py-1 bg-black/90 dark:bg-white px-2${radius==='none'?' rounded-none':' rounded'}`}
-                         style={`left: 50%;transform: translateX(-50%);`} in:fly={{ y: 8, duration: 500 }} out:fly={{ y: 8, duration: 300 }}>
+            <div
+                class={`${
+                    lineBlock
+                        ? 'w-6 h-6 border border-primary dark:border-dark bg-white dark:bg-gray2'
+                        : 'w-5 h-5 ring-4 ring-primary/10 dark:ring-dark/10 bg-primary dark:bg-dark'
+                }${radiusObj[radius] || radiusObj['full']}`}
+                style={`transform: translateX(calc(${currentX}px - 50%));`}
+            >
+                {#if showTip === 'always' || (currentMove === 'one' && showTip !== 'never')}
+                    <div
+                        class={`absolute -top-9 text-white dark:text-black text-xs py-1 bg-black/90 dark:bg-white px-2${
+                            radius === 'none' ? ' rounded-none' : ' rounded'
+                        }`}
+                        style={`left: 50%;transform: translateX(-50%);`}
+                        in:fly={{ y: 8, duration: 500 }}
+                        out:fly={{ y: 8, duration: 300 }}
+                    >
                         {value}
-                        <div class="absolute w-0 h-0 border-4 border-t-4 border-transparent border-t-black/90 dark:border-t-white"
-                             style={`top:100%;left:50%;transform: translateX(-50%)`}></div>
+                        <div
+                            class="absolute w-0 h-0 border-4 border-t-4 border-transparent border-t-black/90 dark:border-t-white"
+                            style={`top:100%;left:50%;transform: translateX(-50%)`}
+                        />
                     </div>
                 {/if}
             </div>
         </div>
     {/if}
-</div>
+</div>

+ 34 - 9
components/src/swiper/Swiper.svelte

@@ -1,12 +1,25 @@
 <script>
     import { onMount, createEventDispatcher } from 'svelte';
 
-    const dispatch = createEventDispatcher(); //事件派发器  event dispatcher
+    // 事件派发器
+    // event dispatcher
+    const dispatch = createEventDispatcher();
 
-    export let data = []; //数据 data
-    export let interval = 4; //间隔时间 interval time
-    export let duration = 1000; //过渡时间 duration time
-    export let autoplay = true; //是否自动播放 is autoplay
+    // 数据
+    // data
+    export let data = [];
+
+    // 间隔时间
+    // interval time
+    export let interval = 4;
+
+    // 过渡时间
+    // duration time
+    export let duration = 1000;
+
+    // 是否自动播放
+    // is autoplay
+    export let autoplay = true;
     export let lazyplay = true; //是否懒轮播 is lazyplay
     export let initActive = 0; //初始激活索引 init active index
     export let indicatePosition = 'inner'; //指示器位置,'inner'/'out'/'none' indicate position
@@ -44,7 +57,9 @@
     let endTime = 0; //滑动结束时间 when end touch time
     let isMove = false; //是否滑动 is touch move
     let transition = true;
+    let swiperDom = null; //Swiper容器
     $: movePercent = moveX / width; //滑动距离占总宽度的百分比 touch width percent
+    
     const dataNew =
         data.length > 1
             ? [data[data.length - 1], ...data, data[0], data[1]]
@@ -238,7 +253,6 @@
             dispatch('change', currentIndicate);
         }, interval * 1000);
     };
-    let swiperDom = null; //Swiper容器
     //判断Swiper容器是否在可视区域内,如果在,则开启定时器,否则不开启定时器
     // Determine whether the Swiper container is in the visible area. If it is, start the timer, otherwise do not start the timer
     const io = new IntersectionObserver(entries => {
@@ -290,16 +304,21 @@
     //滑动开始
     // slide start
     const touchstartFun = e => {
+        // 阻止默认事件
+        // prevent default event
+        e.preventDefault();
         isMove = true;
         startTime = new Date().getTime();
         translateXTransition = false;
-        startX = e.touches[0].clientX;
+        startX = e.clientX;
     };
     //滑动中
     // slideing
     const touchmoveFun = e => {
+        if (!isMove) return false;
+        swiperDom.setPointerCapture(e.pointerId);
         clearInterval(intervalTime); //清除定时器 clear timer
-        moveX = e.touches[0].clientX - startX;
+        moveX = e.clientX - startX;
     };
     //滑动结束
     // slide end
@@ -404,7 +423,13 @@
     };
 </script>
 
-<div bind:this={swiperDom} on:touchstart={touchstartFun} on:touchmove|passive={touchmoveFun} on:touchend={touchendFun}>
+<div
+    bind:this={swiperDom}
+    on:pointerdown={touchstartFun}
+    on:pointermove={touchmoveFun}
+    on:pointerup={touchendFun}
+    class="touch-none cursor-move"
+>
     <!-- 轮播容器 -->
     <!-- Carousel container -->
     <div

+ 9 - 9
demo/package.json

@@ -3,6 +3,15 @@
     "private": true,
     "version": "0.0.0",
     "type": "module",
+    "devDependencies": {
+        "@sveltejs/vite-plugin-svelte": "^2.0.2",
+        "autoprefixer": "^10.4.13",
+        "postcss": "^8.4.19",
+        "svelte": "^3.55.1",
+        "svelte-spa-router": "^3.3.0",
+        "tailwindcss": "^3.2.4",
+        "vite": "^4.1.3"
+    },
     "scripts": {
         "dev": "vite",
         "build": "vite build",
@@ -82,14 +91,5 @@
         "timePicker_en": "vite --mode timePicker_en",
         "calendar_en": "vite --mode calendar_en",
         "pagination_en": "vite --mode pagination_en"
-    },
-    "devDependencies": {
-        "@sveltejs/vite-plugin-svelte": "^2.0.2",
-        "autoprefixer": "^10.4.13",
-        "postcss": "^8.4.19",
-        "svelte": "^3.55.1",
-        "svelte-spa-router": "^3.3.0",
-        "tailwindcss": "^3.2.4",
-        "vite": "^4.1.3"
     }
 }

+ 1 - 7
demo/src/pages/bottomSheet/BottomSheetDemo.svelte

@@ -1,11 +1,8 @@
 <!-- BottomSheet Demo -->
 <script>
-    import { getContext } from 'svelte';
-    import { BottomSheet, Cell, Toast, Button, NoticeBar } from '../../../../components';
+    import { BottomSheet, Cell, Toast, Button } from '../../../../components';
     import Aphorism from '../../components/Aphorism.svelte';
 
-    const isIframe = getContext('iframe') === '1'; //判断是否是iframe
-
     let visible1 = false;
     let visible2 = false;
     let visible3 = false;
@@ -29,9 +26,6 @@
     const heightChangeFunc = e => (currentHeight = e.detail);
 </script>
 
-{#if isIframe}
-    <NoticeBar textList={['BottomSheet 头部区域绑定了 Touch 事件,请直接在移动设备或通过开发者工具模拟移动设备预览。']} right="none" />
-{/if}
 <div class="py-4">
     <Cell title="基础用法" on:click={() => (visible1 = true)} />
     <BottomSheet bind:visible={visible1} title="此区域支持滑动">

+ 1 - 11
demo/src/pages/bottomSheet/BottomSheetDemo_en.svelte

@@ -1,10 +1,8 @@
 <!-- BottomSheet Demo -->
 <script>
-    import { getContext } from 'svelte';
-    import { BottomSheet, Cell, Toast, Button, NoticeBar } from '../../../../components';
+    import { BottomSheet, Cell, Toast, Button } from '../../../../components';
     import Aphorism from '../../components/Aphorism.svelte';
 
-    const isIframe = getContext('iframe') === '1'; //Determine whether it is iframe
     let visible1 = false;
     let visible2 = false;
     let visible3 = false;
@@ -28,14 +26,6 @@
     const heightChangeFunc = e => (currentHeight = e.detail);
 </script>
 
-{#if isIframe}
-    <NoticeBar
-        textList={[
-            'The Touch event is bound to the BottomSheet head area, Please preview the mobile device directly on the mobile device or through the developer tool.',
-        ]}
-        right="none"
-    />
-{/if}
 <div class="py-4">
     <Cell title="Basic usage" on:click={() => (visible1 = true)} />
     <BottomSheet bind:visible={visible1} title="This area supports sliding">

+ 1 - 9
demo/src/pages/indexBar/IndexBarDemo.svelte

@@ -1,9 +1,6 @@
 <!-- IndexBar Demo -->
 <script>
-    import { getContext } from 'svelte';
-    import { IndexBar, Button, NoticeBar, Toast } from '../../../../components';
-
-    const isIframe = getContext('iframe') === '1'; //判断是否是iframe
+    import { IndexBar, Button, Toast } from '../../../../components';
 
     const addressList = [
         { index: 'A', title: 'A', child: [{ text: '澳门' }, { text: '安宁' }, { text: '安庆' }, { text: '鞍山' }] },
@@ -173,11 +170,6 @@
     message={`点击了第 ${toastObj.index + 1} 组(${toastObj.group.title})中的第 ${toastObj.childIndex + 1} 项(${toastObj.child.text})`}
 />
 
-{#if isIframe}
-    <div class="fixed top-12 w-full bg-white dark:bg-gray1">
-        <NoticeBar textList={['右侧 Bar 区域绑定了 Touch 事件,请直接在移动设备或通过开发者工具模拟移动设备预览。']} right="none" />
-    </div>
-{/if}
 <div class="sticky flex justify-between bottom-0 px-2 z-10 bg-white/90 dark:bg-black/90">
     <Button fill="lineTheme" size="auto" injClass="text-xs px-2" on:click={changeListFun}>切换数据</Button>
     <Button fill="lineTheme" size="auto" injClass="text-xs px-2" on:click={changeScrollAlignFun}>

+ 1 - 9
demo/src/pages/indexBar/IndexBarDemo_en.svelte

@@ -1,9 +1,6 @@
 <!-- IndexBar Demo -->
 <script>
-    import { getContext } from 'svelte';
-    import { IndexBar, Button, NoticeBar, Toast } from '../../../../components';
-
-    const isIframe = getContext('iframe') === '1'; //Determine whether it is iframe
+    import { IndexBar, Button, Toast } from '../../../../components';
 
     const addressList = [
         { index: 'A', title: 'A', child: [{ text: 'Macau' }, { text: 'Anning' }, { text: 'Anqing' }, { text: 'Anshan' }] },
@@ -174,11 +171,6 @@
     message={`Clicked ${toastObj.index + 1} group(${toastObj.group.title}) ${toastObj.childIndex + 1} item(${toastObj.child.text})`}
 />
 
-{#if isIframe}
-    <div class="fixed top-12 w-full bg-white dark:bg-gray1">
-        <NoticeBar textList={['The Touch event is bound to the BAR area on the right,Please preview the mobile device directly on the mobile device or through the developer tool.']} right="none" />
-    </div>
-{/if}
 <div class="sticky flex justify-between bottom-0 px-2 z-10 bg-white/90 dark:bg-black/90">
     <Button fill="lineTheme" size="auto" injClass="text-xs px-2" on:click={changeListFun}>Switch data</Button>
     <Button fill="lineTheme" size="auto" injClass="text-xs px-2" on:click={changeScrollAlignFun}>

+ 1 - 9
demo/src/pages/slider/SliderDemo.svelte

@@ -1,10 +1,6 @@
 <!-- Slider Demo -->
 <script>
-    import { getContext } from 'svelte';
-    import { Slider, Icon, NoticeBar } from '../../../../components';
-
-    //判断是否是iframe
-    const isIframe = getContext('iframe') === '1';
+    import { Slider, Icon } from '../../../../components';
 
     let value = 20;
     const onChangeFun = e => {
@@ -35,10 +31,6 @@
     };
 </script>
 
-{#if isIframe}
-    <NoticeBar textList={['Slider 区域绑定了 Touch 事件,请直接在移动设备或通过开发者工具模拟移动设备预览。']} right="none" />
-{/if}
-
 <div class="mx-4 mt-8 font-bold text-lg">基础用法</div>
 <div class="px-6 py-4">
     <Slider />

+ 1 - 9
demo/src/pages/slider/SliderDemo_en.svelte

@@ -1,10 +1,6 @@
 <!-- Slider Demo -->
 <script>
-    import { getContext } from 'svelte';
-    import { Slider, Icon, NoticeBar } from '../../../../components';
-
-    //Check whether it is an iframe
-    const isIframe = getContext('iframe') === '1';
+    import { Slider, Icon } from '../../../../components';
 
     let value = 20;
     const onChangeFun = e => {
@@ -35,10 +31,6 @@
     };
 </script>
 
-{#if isIframe}
-    <NoticeBar textList={['The Slider area is bound to the Touch event, please simulate the mobile preview directly on the mobile device or through the developer tools.']} right="none" />
-{/if}
-
 <div class="mx-4 mt-8 font-bold text-lg">Basic usage</div>
 <div class="px-6 py-4">
     <Slider />

+ 1 - 13
demo/src/pages/timePicker/TimePickerDemo.svelte

@@ -1,10 +1,6 @@
 <!-- TimePickerDemo Demo -->
 <script>
-    import { getContext } from 'svelte';
-    import { Cell, TimePicker, NoticeBar } from '../../../../components';
-
-    //判断是否是iframe
-    const isIframe = getContext('iframe') === '1';
+    import { Cell, TimePicker } from '../../../../components';
 
     let visible1 = false;
     let visible2 = false;
@@ -48,14 +44,6 @@
     };
 </script>
 
-{#if isIframe}
-    <NoticeBar
-        textList={[
-            '当手指滑动(非滚动)年月区域时会动态更新天数列数据,监听了 Touch 事件,请直接在移动设备或通过开发者工具模拟移动设备预览。',
-        ]}
-        right="none"
-    />
-{/if}
 <div class="py-4">
     <div class="px-4">
         {#if defaultTimeStr !== ''}

+ 16 - 16
demo/src/pages/timePicker/TimePickerDemo_en.svelte

@@ -1,10 +1,6 @@
 <!-- TimePickerDemo Demo -->
 <script>
-    import { getContext } from 'svelte';
-    import { Cell, TimePicker, NoticeBar } from '../../../../components';
-
-    //Check whether it is an iframe
-    const isIframe = getContext('iframe') === '1';
+    import { Cell, TimePicker } from '../../../../components';
 
     let visible1 = false;
     let visible2 = false;
@@ -48,14 +44,6 @@
     };
 </script>
 
-{#if isIframe}
-    <NoticeBar
-        textList={[
-            'Dynamic update of day series data when finger is swiping (not scrolling) in the month/year area. Listening for Touch events. Please simulate mobile preview directly on mobile device or through developer tools.',
-        ]}
-        right="none"
-    />
-{/if}
 <div class="py-4">
     <div class="px-4">
         {#if defaultTimeStr !== ''}
@@ -65,13 +53,21 @@
             <div>Please select the time</div>
         {/if}
     </div>
-    <Cell title="Basic usage" subTitle="By default, the current time is selected. 10 years is optional" on:click={() => (visible1 = true)} />
+    <Cell
+        title="Basic usage"
+        subTitle="By default, the current time is selected. 10 years is optional"
+        on:click={() => (visible1 = true)}
+    />
     <TimePicker bind:visible={visible1} on:confirm={getDefaultFunc} />
 
     <Cell title="Just the year, the month and the day" on:click={() => (visible2 = true)} />
     <TimePicker bind:visible={visible2} type="YMD" />
 
-    <Cell title="Misrepresentation unsupported type" subTitle="Use the default year, month, day, hour and second" on:click={() => (visible7 = true)} />
+    <Cell
+        title="Misrepresentation unsupported type"
+        subTitle="Use the default year, month, day, hour and second"
+        on:click={() => (visible7 = true)}
+    />
     <TimePicker bind:visible={visible7} type="MD" />
 
     <Cell title="Just use the minutes and seconds" on:click={() => (visible3 = true)} />
@@ -121,7 +117,11 @@
             <div>Please select the time</div>
         {/if}
     </div>
-    <Cell title="User-defined return time format" subTitle="The output format is Y year M month D day h hour m minute s second" on:click={() => (visible15 = true)} />
+    <Cell
+        title="User-defined return time format"
+        subTitle="The output format is Y year M month D day h hour m minute s second"
+        on:click={() => (visible15 = true)}
+    />
     <TimePicker bind:visible={visible15} outFormat="Y year, M month, D day, h hour, m minutes, s seconds" on:confirm={customFormatFunc} />
 
     <div class="px-4">

+ 4 - 0
doc/guide/changelog.md

@@ -1,3 +1,7 @@
+## 0.1.5
+
+-   修改组件内部的触摸事件为指针事件,使其同时支持鼠标、触控笔和触摸等各种输入方式,包含组件:BottomSheet、IndexBar、Slider、Swiper。关联 [Issues](https://github.com/dufu1991/stdf/issues/5)。[!issue|shenliqing|]
+
 ## 0.1.4
 
 -   更新 NPM README。

+ 4 - 0
doc/guide/changelog_en.md

@@ -1,3 +1,7 @@
+## 0.1.5
+
+-   Modify the touch events in the components to pointer events, enabling support for various input methods such as mouse, stylus, and touch. The components include BottomSheet, IndexBar, Slider, and Swiper. Related to [Issues](https://github.com/dufu1991/stdf/issues/5). [!issue|shenliqing|]
+
 ## 0.1.4
 
 -   Update NPM README.