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

我想知道是否有一种解决方案可以同时适用于iPhone和Android手机上的网站。


当前回答

如果有人试图在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上的滑动不会被检测到,除非它是一个非常长、精确和快速的滑动。

这两条线可以正常工作

其他回答

根据@givanse的回答,以下是你可以用类来做的:

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();

你可以监听touchstart和touchend事件,并根据事件数据计算方向和力(Codepen):

让start = null; 文档。addEventListener('touchstart', e => { const touch = e. changedtouchs[0]; Start = [touch.]clientX touch.clientY); }); 文档。addEventListener('touchend', e => { const touch = e. changedtouchs[0]; Const end = [touch.]clientX touch.clientY); document.body.innerText = " ${结束[0]-[0]开始},${结束[1]-[1]开始}'; }); 点击这里

或者你可以围绕同样的概念构建一个更符合人体工程学的API (Codepen):

const removeListener = addSwipeRightListener(document, (force, e) => {
  console.info('Swiped right with force: ' + force);
});
// removeListener()

// swipe.js const { addSwipeLeftListener, addSwipeRightListener, addSwipeUpListener, addSwipeDownListener, } = (function() { // <element, {listeners: [...], handleTouchstart, handleTouchend}> const elements = new WeakMap(); function readTouch(e) { const touch = e.changedTouches[0]; if (touch == undefined) { return null; } return [touch.clientX, touch.clientY]; } function addListener(element, cb) { let elementValues = elements.get(element); if (elementValues === undefined) { const listeners = new Set(); const handleTouchstart = e => { elementValues.start = readTouch(e); }; const handleTouchend = e => { const start = elementValues.start; if (start === null) { return; } const end = readTouch(e); for (const listener of listeners) { listener([end[0] - start[0], end[1] - start[1]], e); } }; element.addEventListener('touchstart', handleTouchstart); element.addEventListener('touchend', handleTouchend); elementValues = { start: null, listeners, handleTouchstart, handleTouchend, }; elements.set(element, elementValues); } elementValues.listeners.add(cb); return () => deleteListener(element, cb); } function deleteListener(element, cb) { const elementValues = elements.get(element); const listeners = elementValues.listeners; listeners.delete(cb); if (listeners.size === 0) { elements.delete(element); element.removeEventListener('touchstart', elementValues.handleTouchstart); element.removeEventListener('touchend', elementValues.handleTouchend); } } function addSwipeLeftListener(element, cb) { return addListener(element, (force, e) => { const [x, y] = force; if (x < 0 && -x > Math.abs(y)) { cb(x, e); } }); } function addSwipeRightListener(element, cb) { return addListener(element, (force, e) => { const [x, y] = force; if (x > 0 && x > Math.abs(y)) { cb(x, e); } }); } function addSwipeUpListener(element, cb) { return addListener(element, (force, e) => { const [x, y] = force; if (y < 0 && -y > Math.abs(x)) { cb(x, e); } }); } function addSwipeDownListener(element, cb) { return addListener(element, (force, e) => { const [x, y] = force; if (y > 0 && y > Math.abs(x)) { cb(x, e); } }); } return { addSwipeLeftListener, addSwipeRightListener, addSwipeUpListener, addSwipeDownListener, } })(); // app.js function print(direction, force) { document.querySelector('#direction').innerText = direction; document.querySelector('#data').innerText = force; } addSwipeLeftListener(document, (force, e) => { print('left', force); }); addSwipeRightListener(document, (force, e) => { print('right', force); }); addSwipeUpListener(document, (force, e) => { print('up', force); }); addSwipeDownListener(document, (force, e) => { print('down', force); }); <h1>Swipe <span id="direction"></span></h1> Force (px): <span id="data"></span>

一些mod的顶部回答(不能评论…)来处理短滑动

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;
    }
};

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

刷卡

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

swiped-left

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

swiped-right

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

swiped-up

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

swiped-down

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>

要在应用程序范围内设置默认值,请在最顶部的元素上设置配置属性:

<body data-swipe-threshold="100" data-swipe-timeout="250">
    <div>Swipe me</div>
    <div>or me</div>
</body>

源代码可在Github

我只想检测左右滑动,但只在触摸事件结束时触发动作,所以我稍微修改了@givanse的答案来实现这一点。

为什么要这么做?例如,在滑动时,用户注意到他最终不想滑动,他可以将手指移动到原来的位置(一个非常流行的“约会”手机应用程序可以做到这一点;)),然后“向右滑动”事件被取消。

因此,为了避免因为水平上有3px的差异而导致“向右滑动”事件,我添加了一个阈值,在该阈值下事件将被丢弃:为了有一个“向右滑动”事件,用户必须至少滑动浏览器宽度的1/3(当然,您可以修改这个)。

所有这些小细节都增强了用户体验。

请注意,目前,如果两个手指中的一个在缩放过程中做了一个大的水平移动,那么“触摸缩放”可能会被检测为滑动。

这是(Vanilla JS)代码:

var xDown = null, yDown = null, xUp = null, yUp = null;
document.addEventListener('touchstart', touchstart, false);        
document.addEventListener('touchmove', touchmove, false);
document.addEventListener('touchend', touchend, false);
function touchstart(evt) { const firstTouch = (evt.touches || evt.originalEvent.touches)[0]; xDown = firstTouch.clientX; yDown = firstTouch.clientY; }
function touchmove(evt) { if (!xDown || !yDown ) return; xUp = evt.touches[0].clientX; yUp = evt.touches[0].clientY; }
function touchend(evt) { 
    var xDiff = xUp - xDown, yDiff = yUp - yDown;
    if ((Math.abs(xDiff) > Math.abs(yDiff)) && (Math.abs(xDiff) > 0.33 * document.body.clientWidth)) { 
        if (xDiff < 0) 
            document.getElementById('leftnav').click();
        else
            document.getElementById('rightnav').click();
    } 
    xDown = null, yDown = null;
}