首页 文章

在iPhone和Android上通过JavaScript检测手指滑动

提问于
浏览
222

如何检测用户使用JavaScript在网页上向某个方向滑动手指?

我想知道是否有一个解决方案适用于iPhone和Android手机上的网站 .

16 回答

  • 18

    简单的vanilla JS代码示例:

    document.addEventListener('touchstart', handleTouchStart, false);        
    document.addEventListener('touchmove', handleTouchMove, false);
    
    var xDown = null;                                                        
    var yDown = null;
    
    function getTouches(evt) {
      return evt.touches ||             // browser API
             evt.originalEvent.touches; // jQuery
    }                                                     
    
    function handleTouchStart(evt) {
        const firstTouch = getTouches(evt)[0];                                      
        xDown = firstTouch.clientX;                                      
        yDown = firstTouch.clientY;                                      
    };                                                
    
    function handleTouchMove(evt) {
        if ( ! xDown || ! yDown ) {
            return;
        }
    
        var xUp = evt.touches[0].clientX;                                    
        var yUp = evt.touches[0].clientY;
    
        var xDiff = xDown - xUp;
        var yDiff = yDown - yUp;
    
        if ( Math.abs( xDiff ) > Math.abs( yDiff ) ) {/*most significant*/
            if ( xDiff > 0 ) {
                /* left swipe */ 
            } else {
                /* right swipe */
            }                       
        } else {
            if ( yDiff > 0 ) {
                /* up swipe */ 
            } else { 
                /* down swipe */
            }                                                                 
        }
        /* reset values */
        xDown = null;
        yDown = null;                                             
    };
    

    在Android中测试过 .

  • 0

    我发现这个jquery touchwipe插件适用于我的第一代ipod touch和我的droid令人难以置信 . http://www.netcu.de/jquery-touchwipe-iphone-ipad-library

  • 4

    根据@ givanse的回答,这就是你如何用_2685309做到的:

    class Swipe {
        constructor(element) {
            this.xDown = null;
            this.yDown = null;
            this.element = typeof(element) === 'string' ? document.querySelector(element) : element;
    
            this.element.addEventListener('touchstart', function(evt) {
                this.xDown = evt.touches[0].clientX;
                this.yDown = evt.touches[0].clientY;
            }.bind(this), false);
    
        }
    
        onLeft(callback) {
            this.onLeft = callback;
    
            return this;
        }
    
        onRight(callback) {
            this.onRight = callback;
    
            return this;
        }
    
        onUp(callback) {
            this.onUp = callback;
    
            return this;
        }
    
        onDown(callback) {
            this.onDown = callback;
    
            return this;
        }
    
        handleTouchMove(evt) {
            if ( ! this.xDown || ! this.yDown ) {
                return;
            }
    
            var xUp = evt.touches[0].clientX;
            var yUp = evt.touches[0].clientY;
    
            this.xDiff = this.xDown - xUp;
            this.yDiff = this.yDown - yUp;
    
            if ( Math.abs( this.xDiff ) > Math.abs( this.yDiff ) ) { // Most significant.
                if ( this.xDiff > 0 ) {
                    this.onLeft();
                } else {
                    this.onRight();
                }
            } else {
                if ( this.yDiff > 0 ) {
                    this.onUp();
                } else {
                    this.onDown();
                }
            }
    
            // Reset values.
            this.xDown = null;
            this.yDown = null;
        }
    
        run() {
            this.element.addEventListener('touchmove', function(evt) {
                this.handleTouchMove(evt).bind(this);
            }.bind(this), false);
        }
    }
    

    你可以像这样使用它:

    // Use class to get element by string.
    var swiper = new Swipe('#my-element');
    swiper.onLeft(function() { alert('You swiped left.') });
    swiper.run();
    
    // Get the element yourself.
    var swiper = new Swipe(document.getElementById('#my-element'));
    swiper.onLeft(function() { alert('You swiped left.') });
    swiper.run();
    
    // One-liner.
    (new Swipe('#my-element')).onLeft(function() { alert('You swiped left.') }).run();
    
  • 14

    你试过hammer.js吗? http://eightmedia.github.com/hammer.js/也适用于Windows手机..

  • 8

    之前我用过的是你必须检测mousedown事件,记录它的x,y位置(以相关者为准)然后检测mouseup事件,然后减去这两个值 .

  • 42

    jQuery Mobile还包括滑动支持:http://api.jquerymobile.com/swipe/

    $("#divId").on("swipe", function(event) {
        alert("It's a swipe!");
    });
    
  • 2

    我发现@givanse很棒的答案是在多个移动浏览器中最可靠和最兼容的注册滑动操作 .

    但是,在使用 jQuery 的现代移动浏览器中使其工作所需的代码发生了变化 .

    如果使用 jQueryevent.touches 将不存在,结果为 undefined ,应由 event.originalEvent.touches 替换 . 没有 jQueryevent.touches 应该可以正常工作 .

    所以解决方案变成,

    document.addEventListener('touchstart', handleTouchStart, false);        
    document.addEventListener('touchmove', handleTouchMove, false);
    
    var xDown = null;                                                        
    var yDown = null;                                                        
    
    function handleTouchStart(evt) {                                         
        xDown = evt.originalEvent.touches[0].clientX;                                      
        yDown = evt.originalEvent.touches[0].clientY;                                      
    };                                                
    
    function handleTouchMove(evt) {
        if ( ! xDown || ! yDown ) {
            return;
        }
    
        var xUp = evt.originalEvent.touches[0].clientX;                                    
        var yUp = evt.originalEvent.touches[0].clientY;
    
        var xDiff = xDown - xUp;
        var yDiff = yDown - yUp;
    
        if ( Math.abs( xDiff ) > Math.abs( yDiff ) ) {/*most significant*/
            if ( xDiff > 0 ) {
                /* left swipe */ 
            } else {
                /* right swipe */
            }                       
        } else {
            if ( yDiff > 0 ) {
                /* up swipe */ 
            } else { 
                /* down swipe */
            }                                                                 
        }
        /* reset values */
        xDown = null;
        yDown = null;                                             
    };
    

    测试:

    • Android :Chrome,UC浏览器

    • iOS :Safari,Chrome,UC浏览器

  • 26

    我将TouchWipe重新打包为一个简短的jquery插件:detectSwipe

  • 6

    我将这里的一些答案合并到一个脚本中,该脚本使用CustomEvent来触发DOM中的滑动事件 . 将0.7k swiped-events.min.js脚本添加到您的页面并监听 swiped 事件:

    向左滑动

    document.addEventListener('swiped-left', function(e) {
        console.log(e.target); // the element that was swiped
    });
    

    向右滑动

    document.addEventListener('swiped-right', function(e) {
        console.log(e.target); // the element that was swiped
    });
    

    刷了起来

    document.addEventListener('swiped-up', function(e) {
        console.log(e.target); // the element that was swiped
    });
    

    刷了下来

    document.addEventListener('swiped-down', function(e) {
        console.log(e.target); // the element that was swiped
    });
    

    您还可以直接附加到元素:

    document.getElementById('myBox').addEventListener('swiped-down', function(e) {
        console.log(e.target); // the element that was swiped
    });
    

    可选配置

    您可以指定以下属性来调整页面中滑动交互功能的方式(这些是可选的) .

    <div data-swipe-threshold="10"
         data-swipe-timeout="1000"
         data-swipe-ignore="false">
            Swiper, get swiping!
    </div>
    

    源代码可在Github获取

  • 0

    一些最新的答案(无法评论......)来处理短暂的滑动

    document.addEventListener('touchstart', handleTouchStart, false);        
    document.addEventListener('touchmove', handleTouchMove, false);
    var xDown = null;                                                        
    var yDown = null;                                                        
    function handleTouchStart(evt) {                                         
        xDown = evt.touches[0].clientX;                                      
        yDown = evt.touches[0].clientY;                                      
    };                                                
    function handleTouchMove(evt) {
        if ( ! xDown || ! yDown ) {
            return;
        }
    
        var xUp = evt.touches[0].clientX;                                    
        var yUp = evt.touches[0].clientY;
    
        var xDiff = xDown - xUp;
        var yDiff = yDown - yUp;
        if(Math.abs( xDiff )+Math.abs( yDiff )>150){ //to deal with to short swipes
    
        if ( Math.abs( xDiff ) > Math.abs( yDiff ) ) {/*most significant*/
            if ( xDiff > 0 ) {/* left swipe */ 
                alert('left!');
            } else {/* right swipe */
                alert('right!');
            }                       
        } else {
            if ( yDiff > 0 ) {/* up swipe */
                alert('Up!'); 
            } else { /* down swipe */
                alert('Down!');
            }                                                                 
        }
        /* reset values */
        xDown = null;
        yDown = null;
        }
    };
    
  • 5

    trashold,超时滑动,swipeBlockElems添加 .

    document.addEventListener('touchstart', handleTouchStart, false);
    document.addEventListener('touchmove', handleTouchMove, false);
    document.addEventListener('touchend', handleTouchEnd, false);     
    
    const SWIPE_BLOCK_ELEMS = [
      'swipBlock',
      'handle',
      'drag-ruble'
    ]
    
    let xDown = null;
    let yDown = null; 
    let xDiff = null;
    let yDiff = null;
    let timeDown = null;
    const  TIME_TRASHOLD = 200;
    const  DIFF_TRASHOLD = 130;
    
    function handleTouchEnd() {
    
    let timeDiff = Date.now() - timeDown; 
    if (Math.abs(xDiff) > Math.abs(yDiff)) { /*most significant*/
      if (Math.abs(xDiff) > DIFF_TRASHOLD && timeDiff < TIME_TRASHOLD) {
        if (xDiff > 0) {
          // console.log(xDiff, TIME_TRASHOLD, DIFF_TRASHOLD)
          SWIPE_LEFT(LEFT) /* left swipe */
        } else {
          // console.log(xDiff)
          SWIPE_RIGHT(RIGHT) /* right swipe */
        }
      } else {
        console.log('swipeX trashhold')
      }
    } else {
      if (Math.abs(yDiff) > DIFF_TRASHOLD && timeDiff < TIME_TRASHOLD) {
        if (yDiff > 0) {
          /* up swipe */
        } else {
          /* down swipe */
        }
      } else {
        console.log('swipeY trashhold')
      }
     }
     /* reset values */
     xDown = null;
     yDown = null;
     timeDown = null; 
    }
    function containsClassName (evntarget , classArr) {
     for (var i = classArr.length - 1; i >= 0; i--) {
       if( evntarget.classList.contains(classArr[i]) ) {
          return true;
        }
      }
    }
    function handleTouchStart(evt) {
      let touchStartTarget = evt.target;
      if( containsClassName(touchStartTarget, SWIPE_BLOCK_ELEMS) ) {
        return;
      }
      timeDown = Date.now()
      xDown = evt.touches[0].clientX;
      yDown = evt.touches[0].clientY;
      xDiff = 0;
      yDiff = 0;
    
    }
    
    function handleTouchMove(evt) {
      if (!xDown || !yDown) {
        return;
      }
    
      var xUp = evt.touches[0].clientX;
      var yUp = evt.touches[0].clientY;
    
    
      xDiff = xDown - xUp;
      yDiff = yDown - yUp;
    }
    
  • 5

    如果有人试图在Android上使用jQuery Mobile并且在JQM滑动检测方面存在问题

    (我有一些关于Xperia Z1,Galaxy S3,Nexus 4和一些Wiko手机)这可能很有用:

    //Fix swipe gesture on android
        if(android){ //Your own device detection here
            $.event.special.swipe.verticalDistanceThreshold = 500
            $.event.special.swipe.horizontalDistanceThreshold = 10
        }
    

    除非是非常长,精确和快速的滑动,否则未检测到在Android上滑动 .

    使用这两行它可以正常工作

  • 281

    当用户拖动手指时,我遇到了touchend处理程序不断触发的问题 . 我不知道这是不是因为我做错了或者没有做错,但是我重写了这个用touchmove积累动作,而touchend实际上是在触发回调 .

    我还需要有大量的这些实例,所以我添加了启用/禁用方法 .

    并且短暂滑动不会触发的阈值 . 每次Touchstart零都是计数器 .

    您可以动态更改target_node . 创建时启用是可选的 .

    /** Usage: */
    touchevent = new Modules.TouchEventClass(callback, target_node);
    touchevent.enable();
    touchevent.disable();
    
    /** 
    *
    *   Touch event module
    *
    *   @param method   set_target_mode
    *   @param method   __touchstart
    *   @param method   __touchmove
    *   @param method   __touchend
    *   @param method   enable
    *   @param method   disable
    *   @param function callback
    *   @param node     target_node
    */
    Modules.TouchEventClass = class {
    
        constructor(callback, target_node, enable=false) {
    
            /** callback function */
            this.callback = callback;
    
            this.xdown = null;
            this.ydown = null;
            this.enabled = false;
            this.target_node = null;
    
            /** move point counts [left, right, up, down] */
            this.counts = [];
    
            this.set_target_node(target_node);
    
            /** Enable on creation */
            if (enable === true) {
                this.enable();
            }
    
        }
    
        /** 
        *   Set or reset target node
        *
        *   @param string/node target_node
        *   @param string      enable (optional)
        */
        set_target_node(target_node, enable=false) {
    
            /** check if we're resetting target_node */
            if (this.target_node !== null) {
    
                /** remove old listener */
               this.disable();
            }
    
            /** Support string id of node */
            if (target_node.nodeName === undefined) {
                target_node = document.getElementById(target_node);
            }
    
            this.target_node = target_node;
    
            if (enable === true) {
                this.enable();
            }
        }
    
        /** enable listener */
        enable() {
            this.enabled = true;
            this.target_node.addEventListener("touchstart", this.__touchstart.bind(this));
            this.target_node.addEventListener("touchmove", this.__touchmove.bind(this));
            this.target_node.addEventListener("touchend", this.__touchend.bind(this));
        }
    
        /** disable listener */
        disable() {
            this.enabled = false;
            this.target_node.removeEventListener("touchstart", this.__touchstart);
            this.target_node.removeEventListener("touchmove", this.__touchmove);
            this.target_node.removeEventListener("touchend", this.__touchend);
        }
    
        /** Touchstart */
        __touchstart(event) {
            event.stopPropagation();
            this.xdown = event.touches[0].clientX;
            this.ydown = event.touches[0].clientY;
    
            /** reset count of moves in each direction, [left, right, up, down] */
            this.counts = [0, 0, 0, 0];
        }
    
        /** Touchend */
        __touchend(event) {
            let max_moves = Math.max(...this.counts);
            if (max_moves > 500) { // set this threshold appropriately
                /** swipe happened */
                let index = this.counts.indexOf(max_moves);
                if (index == 0) {
                    this.callback("left");
                } else if (index == 1) {
                    this.callback("right");
                } else if (index == 2) {
                    this.callback("up");
                } else {
                    this.callback("down");
                }
            }
        }
    
        /** Touchmove */
        __touchmove(event) {
    
            event.stopPropagation();
            if (! this.xdown || ! this.ydown) {
                return;
            }
    
            let xup = event.touches[0].clientX;
            let yup = event.touches[0].clientY;
    
            let xdiff = this.xdown - xup;
            let ydiff = this.ydown - yup;
    
            /** Check x or y has greater distance */
            if (Math.abs(xdiff) > Math.abs(ydiff)) {
                if (xdiff > 0) {
                    this.counts[0] += Math.abs(xdiff);
                } else {
                    this.counts[1] += Math.abs(xdiff);
                }
            } else {
                if (ydiff > 0) {
                    this.counts[2] += Math.abs(ydiff);
                } else {
                    this.counts[3] += Math.abs(ydiff);
                }
            }
        }
    }
    
  • 6

    使用二:

    jQuery mobile: 在大多数情况下工作,特别是在开发使用其他jQuery插件的应用程序时,最好使用jQuery移动控件 . 在这里访问:https://www.w3schools.com/jquerymobile/jquerymobile_events_touch.asp

    Hammer Time ! 最好,轻量级和快速的基于JavaScript的库之一 . 在这里访问:https://hammerjs.github.io/

  • 3

    如果你只是需要滑动,只需使用你需要的部分就可以更好地放大尺寸 . 这适用于任何触摸设备 .

    在gzip压缩,缩小,babel等之后,这是~450个字节 .

    我根据其他答案编写了下面的类,它使用百分比移动而不是像素,并使用事件调度程序模式来挂钩/取消挂钩 .

    像这样使用它:

    const dispatcher = new SwipeEventDispatcher(myElement);
    dispatcher.on('SWIPE_RIGHT', () => { console.log('I swiped right!') })
    
    export class SwipeEventDispatcher {
    	constructor(element, options = {}) {
    		this.evtMap = {
    			SWIPE_LEFT: [],
    			SWIPE_UP: [],
    			SWIPE_DOWN: [],
    			SWIPE_RIGHT: []
    		};
    
    		this.xDown = null;
    		this.yDown = null;
    		this.element = element;
    		this.options = Object.assign({ triggerPercent: 0.3 }, options);
    
    		element.addEventListener('touchstart', evt => this.handleTouchStart(evt), false);
    		element.addEventListener('touchend', evt => this.handleTouchEnd(evt), false);
    	}
    
    	on(evt, cb) {
    		this.evtMap[evt].push(cb);
    	}
    
    	off(evt, lcb) {
    		this.evtMap[evt] = this.evtMap[evt].filter(cb => cb !== lcb);
    	}
    
    	trigger(evt, data) {
    		this.evtMap[evt].map(handler => handler(data));
    	}
    
    	handleTouchStart(evt) {
    		this.xDown = evt.touches[0].clientX;
    		this.yDown = evt.touches[0].clientY;
    	}
    
    	handleTouchEnd(evt) {
    		const deltaX = evt.changedTouches[0].clientX - this.xDown;
    		const deltaY = evt.changedTouches[0].clientY - this.yDown;
    		const distMoved = Math.abs(Math.abs(deltaX) > Math.abs(deltaY) ? deltaX : deltaY);
    		const activePct = distMoved / this.element.offsetWidth;
    
    		if (activePct > this.options.triggerPercent) {
    			if (Math.abs(deltaX) > Math.abs(deltaY)) {
    				deltaX < 0 ? this.trigger('SWIPE_LEFT') : this.trigger('SWIPE_RIGHT');
    			} else {
    				deltaY > 0 ? this.trigger('SWIPE_UP') : this.trigger('SWIPE_DOWN');
    			}
    		}
    	}
    }
    
    export default SwipeEventDispatcher;
    
  • 13

    如何使用偏移量的示例 .

    // at least 100 px are a swipe
    // you can use the value relative to screen size: window.innerWidth * .1
    const offset = 100;
    let xDown, yDown
    
    window.addEventListener('touchstart', e => {
      const firstTouch = getTouch(e);
    
      xDown = firstTouch.clientX;
      yDown = firstTouch.clientY;
    });
    
    window.addEventListener('touchend', e => {
      if (!xDown || !yDown) {
        return;
      }
    
      const {
        clientX: xUp,
        clientY: yUp
      } = getTouch(e);
      const xDiff = xDown - xUp;
      const yDiff = yDown - yUp;
      const xDiffAbs = Math.abs(xDown - xUp);
      const yDiffAbs = Math.abs(yDown - yUp);
    
      // at least <offset> are a swipe
      if (Math.max(xDiffAbs, yDiffAbs) < offset ) {
        return;
      }
    
      if (xDiffAbs > yDiffAbs) {
        if ( xDiff > 0 ) {
          console.log('left');
        } else {
          console.log('right');
        }
      } else {
        if ( yDiff > 0 ) {
          console.log('up');
        } else {
          console.log('down');
        }
      }
    });
    
    function getTouch (e) {
      return e.changedTouches[0]
    }
    

相关问题