瀏覽代碼

Refactoring the Drag component with `changedTouches`. Disable `touch-callout` by default if the drag is enabled.

NaotoshiFujita 3 年之前
父節點
當前提交
3deb842b6f

File diff suppressed because it is too large
+ 0 - 0
dist/css/splide-core.min.css


File diff suppressed because it is too large
+ 0 - 0
dist/css/splide.min.css


File diff suppressed because it is too large
+ 0 - 0
dist/css/themes/splide-default.min.css


File diff suppressed because it is too large
+ 0 - 0
dist/css/themes/splide-sea-green.min.css


File diff suppressed because it is too large
+ 0 - 0
dist/css/themes/splide-skyblue.min.css


+ 1 - 0
dist/types/index.d.ts

@@ -829,6 +829,7 @@ declare class Splide {
         MOUNTED: number;
         IDLE: number;
         MOVING: number;
+        DRAGGING: number;
         DESTROYED: number;
     };
     /**

+ 2 - 2
package-lock.json

@@ -1,12 +1,12 @@
 {
   "name": "@splidejs/splide",
-  "version": "3.6.13",
+  "version": "3.6.14",
   "lockfileVersion": 2,
   "requires": true,
   "packages": {
     "": {
       "name": "@splidejs/splide",
-      "version": "3.6.13",
+      "version": "3.6.14",
       "license": "MIT",
       "devDependencies": {
         "@babel/core": "^7.16.10",

+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "@splidejs/splide",
-  "version": "3.6.13",
+  "version": "3.6.14",
   "description": "Splide is a lightweight, flexible and accessible slider/carousel. No dependencies, no Lighthouse errors.",
   "author": "Naotoshi Fujita",
   "license": "MIT",

+ 2 - 2
scripts/build-script.js

@@ -22,7 +22,7 @@ async function buildScript( compress, type = 'default' ) {
         configFile: path.resolve( __dirname, '../.babelrc' ),
         allowAllFormats: true,
       } ),
-      compress ? minify() : false,
+      compress ? minify( { minify: { sourceMap: true } } ) : false,
     ]
   } );
 
@@ -31,7 +31,7 @@ async function buildScript( compress, type = 'default' ) {
     file,
     format   : 'umd',
     name     : type === 'default' ? 'Splide' : 'SplideRenderer',
-    sourcemap: ! compress,
+    sourcemap: compress,
   } );
 
   if ( compress && type === 'default' ) {

+ 3 - 2
scripts/plugins/minify.js

@@ -1,8 +1,9 @@
 const uglify = require( 'uglify-js' );
+const plugin = require( 'rollup-plugin-dts' );
 
 const DEFAULTS = {
   minify: {
-    sourceMap: false,
+	  sourceMap: true,
     output: {
       comments: /^!/,
     },
@@ -27,7 +28,7 @@ function minify( pluginOptions = {} ) {
         throw new Error( result.error );
       }
 
-      return result.code;
+      return result;
     },
   }
 }

+ 1 - 0
src/css/core/object/modifiers/draggable.scss

@@ -5,6 +5,7 @@
     > #{ $root }__slider > #{ $root }__track,
     > #{ $root }__track {
       user-select: none;
+      -webkit-touch-callout: none;
     }
   }
 }

+ 106 - 86
src/js/components/Drag/Drag.ts

@@ -1,5 +1,6 @@
 import { EVENT_DRAG, EVENT_DRAGGED, EVENT_DRAGGING, EVENT_MOUNTED, EVENT_UPDATED } from '../../constants/events';
 import { SCROLL_LISTENER_OPTIONS } from '../../constants/listener-options';
+import { DRAGGING, IDLE, MOVING } from '../../constants/states';
 import { FADE, LOOP, SLIDE } from '../../constants/types';
 import { EventInterface } from '../../constructors';
 import { Splide } from '../../core/Splide/Splide';
@@ -31,6 +32,7 @@ export interface DragComponent extends BaseComponent {
  */
 export function Drag( Splide: Splide, Components: Components, options: Options ): DragComponent {
   const { on, emit, bind, unbind } = EventInterface( Splide );
+  const { state } = Splide;
   const { Move, Scroll, Controller } = Components;
   const { track } = Components.Elements;
   const { resolve, orient } = Components.Direction;
@@ -51,11 +53,6 @@ export function Drag( Splide: Splide, Components: Components, options: Options )
    */
   let prevBaseEvent: TouchEvent | MouseEvent;
 
-  /**
-   * Keeps the last TouchEvent/MouseEvent object on pointermove.
-   */
-  let lastEvent: TouchEvent | MouseEvent;
-
   /**
    * Indicates whether the drag mode is `free` or not.
    */
@@ -70,7 +67,7 @@ export function Drag( Splide: Splide, Components: Components, options: Options )
    * Indicates whether the slider exceeds limits or not.
    * This must not be `undefined` for strict comparison.
    */
-  let hasExceeded = false;
+  let exceeded = false;
 
   /**
    * Turns into `true` when the user starts dragging the slider.
@@ -96,7 +93,6 @@ export function Drag( Splide: Splide, Components: Components, options: Options )
     bind( track, POINTER_DOWN_EVENTS, onPointerDown, SCROLL_LISTENER_OPTIONS );
     bind( track, 'click', onClick, { capture: true } );
     bind( track, 'dragstart', prevent );
-
     on( [ EVENT_MOUNTED, EVENT_UPDATED ], init );
   }
 
@@ -111,24 +107,25 @@ export function Drag( Splide: Splide, Components: Components, options: Options )
 
   /**
    * Called when the user clicks or touches the slider.
-   * Needs to prevent the default behaviour when the slider is busy to deny any action, such as dragging images.
-   * Note that IE does not support MouseEvent and TouchEvent constructors.
+   * - Needs to prevent the default behaviour when the slider is busy to deny any action, such as dragging images
+   * - IE does not support MouseEvent and TouchEvent constructors
+   * - The `dragging` state always becomes `true` when the user starts dragging while the slider is moving
    *
    * @param e - A TouchEvent or MouseEvent object
    */
   function onPointerDown( e: TouchEvent | MouseEvent ): void {
+    clickPrevented = false;
+
     if ( ! disabled ) {
       const { noDrag } = options;
       const isTouch     = isTouchEvent( e );
       const isDraggable = ! noDrag || ! matches( e.target, noDrag );
 
-      clickPrevented = false;
-
       if ( isDraggable && ( isTouch || ! e.button ) ) {
         if ( ! Move.isBusy() ) {
           target        = isTouch ? track : window;
           prevBaseEvent = null;
-          lastEvent     = null;
+          dragging      = state.is( MOVING );
 
           bind( target, POINTER_MOVE_EVENTS, onPointerMove, SCROLL_LISTENER_OPTIONS );
           bind( target, POINTER_UP_EVENTS, onPointerUp, SCROLL_LISTENER_OPTIONS );
@@ -148,83 +145,82 @@ export function Drag( Splide: Splide, Components: Components, options: Options )
    * @param e - A TouchEvent or MouseEvent object
    */
   function onPointerMove( e: TouchEvent | MouseEvent ): void {
-    if ( ! lastEvent ) {
+    if ( ! state.is( DRAGGING ) ) {
+      state.set( DRAGGING );
       emit( EVENT_DRAG );
     }
 
-    lastEvent = e;
-
     if ( e.cancelable ) {
-      const diff = coordOf( e ) - coordOf( baseEvent );
-
       if ( dragging ) {
-        Move.translate( basePosition + constrain( diff ) );
+        Move.translate( basePosition + constrain( diffCoord( e ) ) );
 
-        const expired  = timeOf( e ) - timeOf( baseEvent ) > LOG_INTERVAL;
-        const exceeded = hasExceeded !== ( hasExceeded = exceededLimit() );
+        const expired     = diffTime( e ) > LOG_INTERVAL;
+        const hasExceeded = exceeded !== ( exceeded = exceededLimit() );
 
-        if ( expired || exceeded ) {
+        if ( expired || hasExceeded ) {
           save( e );
         }
 
-        emit( EVENT_DRAGGING );
         clickPrevented = true;
+        emit( EVENT_DRAGGING );
+        prevent( e );
+      } else if ( isSliderDirection( e ) ) {
+        dragging = shouldStart( e );
         prevent( e );
-      } else {
-        let { dragMinThreshold: thresholds } = options;
-        thresholds = isObject( thresholds ) ? thresholds : { mouse: 0, touch: +thresholds || 10 };
-        dragging   = abs( diff ) > ( isTouchEvent( e ) ? thresholds.touch : thresholds.mouse );
-
-        if ( isSliderDirection() ) {
-          prevent( e );
-        }
       }
     }
   }
 
   /**
    * Called when the user releases pointing devices.
-   * Be aware that the TouchEvent object provided by the `touchend` does not contain `Touch` objects,
-   * which means the last touch position is not available.
+   * Needs to move the slider when:
+   * - The user drags the slider and the distance exceeds the threshold
+   * - The user aborted the slider moving by pointerdown and just released it without dragging the slider
    *
    * @param e - A TouchEvent or MouseEvent object
    */
   function onPointerUp( e: TouchEvent | MouseEvent ): void {
-    unbind( target, POINTER_MOVE_EVENTS, onPointerMove );
-    unbind( target, POINTER_UP_EVENTS, onPointerUp );
-
-    const { index } = Splide;
-
-    if ( lastEvent ) {
-      if ( dragging || ( e.cancelable && isSliderDirection() ) ) {
-        const velocity    = computeVelocity( e );
-        const destination = computeDestination( velocity );
+    if ( state.is( DRAGGING ) ) {
+      state.set( IDLE );
+      emit( EVENT_DRAGGED );
+    }
 
-        if ( isFree ) {
-          Controller.scroll( destination );
-        } else if ( Splide.is( FADE ) ) {
-          Controller.go( index + orient( sign( velocity ) ) );
-        } else {
-          Controller.go( Controller.toDest( destination ), true );
-        }
+    if ( dragging ) {
+      const velocity    = computeVelocity( e );
+      const destination = computeDestination( velocity );
 
-        prevent( e );
+      if ( isFree ) {
+        Controller.scroll( destination );
+      } else if ( Splide.is( FADE ) ) {
+        Controller.go( Splide.index + orient( sign( velocity ) ) );
+      } else {
+        Controller.go( Controller.toDest( destination ), true );
       }
 
-      emit( EVENT_DRAGGED );
-    } else {
-      if ( ! isFree && getPosition() !== Move.toPosition( index ) ) {
-        Controller.go( index, true );
-      }
+      prevent( e );
     }
 
+    unbind( target, POINTER_MOVE_EVENTS, onPointerMove );
+    unbind( target, POINTER_UP_EVENTS, onPointerUp );
     dragging = false;
   }
 
+  /**
+   * Called when the track element is clicked.
+   * Disables click any elements inside it while dragging.
+   *
+   * @param e - A MouseEvent object.
+   */
+  function onClick( e: MouseEvent ): void {
+    if ( ! disabled && clickPrevented ) {
+      prevent( e, true );
+    }
+  }
+
   /**
    * Saves data at the specific moment.
    *
-   * @param e  A TouchEvent or MouseEvent object
+   * @param e - A TouchEvent or MouseEvent object
    */
   function save( e: TouchEvent | MouseEvent ): void {
     prevBaseEvent = baseEvent;
@@ -233,26 +229,29 @@ export function Drag( Splide: Splide, Components: Components, options: Options )
   }
 
   /**
-   * Called when the track element is clicked.
-   * Disables click any elements inside it while dragging.
+   * Checks if the drag distance exceeds the defined threshold.
    *
-   * @param e - A MouseEvent object.
+   * @param e - A TouchEvent or MouseEvent object.
+   *
+   * @return `true` if the distance exceeds the threshold, or `false` if not.
    */
-  function onClick( e: MouseEvent ): void {
-    if ( ! disabled && clickPrevented ) {
-      prevent( e, true );
-    }
+  function shouldStart( e: TouchEvent | MouseEvent ): boolean {
+    const { dragMinThreshold: thresholds } = options;
+    const isObj = isObject( thresholds );
+    const mouse = isObj && thresholds.mouse || 0;
+    const touch = ( isObj ? thresholds.touch : +thresholds ) || 10;
+    return abs( diffCoord( e ) ) > ( isTouchEvent( e ) ? touch : mouse );
   }
 
   /**
-   * Checks whether dragging towards the slider or scroll direction.
+   * Checks whether dragging towards the slider or the scroll direction.
+   *
+   * @return `true` if dragging towards the slider direction, or otherwise `false`.
    *
-   * @return `true` if going towards the slider direction, or otherwise `false`.
+   * @param e - A TouchEvent or MouseEvent object
    */
-  function isSliderDirection(): boolean {
-    const diffX = abs( coordOf( lastEvent ) - coordOf( baseEvent ) );
-    const diffY = abs( coordOf( lastEvent, true ) - coordOf( baseEvent, true ) );
-    return diffX > diffY;
+  function isSliderDirection( e: TouchEvent | MouseEvent ): boolean {
+    return abs( diffCoord( e ) ) > abs( diffCoord( e, true ) );
   }
 
   /**
@@ -263,14 +262,11 @@ export function Drag( Splide: Splide, Components: Components, options: Options )
    * @return The drag velocity.
    */
   function computeVelocity( e: TouchEvent | MouseEvent ): number {
-    if ( Splide.is( LOOP ) || ! hasExceeded ) {
-      const base      = baseEvent === lastEvent && prevBaseEvent || baseEvent;
-      const diffCoord = coordOf( lastEvent ) - coordOf( base );
-      const diffTime  = timeOf( e ) - timeOf( base );
-      const isFlick   = timeOf( e ) - timeOf( lastEvent ) < LOG_INTERVAL;
-
-      if ( diffTime && isFlick ) {
-        return diffCoord / diffTime;
+    if ( Splide.is( LOOP ) || ! exceeded ) {
+      const time = diffTime( e );
+
+      if ( time && time < LOG_INTERVAL ) {
+        return diffCoord( e ) / time;
       }
     }
 
@@ -292,27 +288,51 @@ export function Drag( Splide: Splide, Components: Components, options: Options )
   }
 
   /**
-   * Returns the `pageX` and `pageY` coordinates provided by the event.
-   * Be aware that IE does not support both TouchEvent and MouseEvent constructors.
+   * Returns the coord difference between the provided and base events.
    *
    * @param e          - A TouchEvent or MouseEvent object.
    * @param orthogonal - Optional. If `true`, returns the coord of the orthogonal axis against the drag one.
    *
-   * @return A pageX or pageY coordinate.
+   * @return The difference of the coord.
    */
-  function coordOf( e: TouchEvent | MouseEvent, orthogonal?: boolean ): number {
-    return ( isTouchEvent( e ) ? e.touches[ 0 ] : e )[ `page${ resolve( orthogonal ? 'Y' : 'X' ) }` ];
+  function diffCoord( e: TouchEvent | MouseEvent, orthogonal?: boolean ): number {
+    return coordOf( e, orthogonal ) - coordOf( getBaseEvent( e ), orthogonal );
   }
 
   /**
-   * Returns the time stamp in the provided event object.
+   * Returns the elapsed time from the base event to `e`.
    *
    * @param e - A TouchEvent or MouseEvent object.
    *
-   * @return A time stamp.
+   * @return The elapsed time in milliseconds.
    */
-  function timeOf( e: TouchEvent | MouseEvent ): number {
-    return e.timeStamp;
+  function diffTime( e: TouchEvent | MouseEvent ): number {
+    return e.timeStamp - getBaseEvent( e ).timeStamp;
+  }
+
+  /**
+   * Returns the base event.
+   * If the base event is same with `e`, returns previous one.
+   *
+   * @param e - A TouchEvent or MouseEvent object.
+   *
+   * @return A base event.
+   */
+  function getBaseEvent( e: TouchEvent | MouseEvent ): TouchEvent | MouseEvent {
+    return baseEvent === e && prevBaseEvent || baseEvent;
+  }
+
+  /**
+   * Returns the `pageX` and `pageY` coordinates provided by the event.
+   * Be aware that IE does not support both TouchEvent and MouseEvent constructors.
+   *
+   * @param e          - A TouchEvent or MouseEvent object.
+   * @param orthogonal - Optional. If `true`, returns the coord of the orthogonal axis against the drag one.
+   *
+   * @return A pageX or pageY coordinate.
+   */
+  function coordOf( e: TouchEvent | MouseEvent, orthogonal?: boolean ): number {
+    return ( isTouchEvent( e ) ? e.changedTouches[ 0 ] : e )[ `page${ resolve( orthogonal ? 'Y' : 'X' ) }` ];
   }
 
   /**
@@ -324,7 +344,7 @@ export function Drag( Splide: Splide, Components: Components, options: Options )
    * @return The constrained diff.
    */
   function constrain( diff: number ): number {
-    return diff / ( hasExceeded && Splide.is( SLIDE ) ? FRICTION : 1 );
+    return diff / ( exceeded && Splide.is( SLIDE ) ? FRICTION : 1 );
   }
 
   /**

+ 7 - 1
src/js/constants/states.ts

@@ -18,10 +18,15 @@ export const IDLE = 3;
  */
 export const MOVING = 4;
 
+/**
+ * The user is dragging the slider.
+ */
+export const DRAGGING = 5;
+
 /**
  * Splide has been destroyed.
  */
-export const DESTROYED = 5;
+export const DESTROYED = 6;
 
 /**
  * The collection of all states.
@@ -33,5 +38,6 @@ export const STATES = {
   MOUNTED,
   IDLE,
   MOVING,
+  DRAGGING,
   DESTROYED,
 };

Some files were not shown because too many files changed in this diff