JS如何利用定时器实现长按事件

本篇文章由:http://xinpure.com/js-how-to-use-timer-press-event/css

JS 原生事件并无长按事件,可是咱们能够利用一些原有的事件,来实现长按事件html

任务需求

最近在工做上遇到一个特殊的需求,就是须要实现长按来增长或者减小数值jquery

这就相似于,购物车中的物品数量的加减按钮,单击按钮物品数量相应增长或者减小一个数量,利用长按来实现快速增长或者减小物品数量web

JS如何利用定时器实现长按事件

思考方法

在知道这个需求以后,开始仍是比较茫然的测试

虽然在以前我也在一些购物 APP 里见到过这种长按的功能,可是在 JS 里彷佛并无长按事件flex

后来我就在想,怎么样利用现有的一些事件来实现这一功能呢?3d

这个时候我想到了 mousedownmouseup 这两个事件code

当时我就想,若是在 mousedown 事件触发的时候,利用 setTimeout 或者 setInterval 定时增长或者减小数值htm

而后在 mouseup 事件触发的时候,利用 clearTimeout 或者 clearInterval 清除定时器blog

这样是否是就能实现这样的需求呢?

实践想法

既然有了想法,就要付诸实践

我写了个例子来测试这个想法,结果却并无想得这么简单

当我经过鼠标按住按钮以后,数值是不断的增长或者减小,可是即便我松开鼠标,数值却并无中止,而是依然为不断的增长或者减小

这时我就疑惑了,理论上说,在 mouseup 事件触发以后,定时器应该是已经被清除的,为什么没有清除呢?

带着疑惑,我开始了 Google

Google 将我指引到了 Jquery Mobile

这个类库实现了一个 taphold 事件,就是我想要的长按事件

既然已经有了相似的实现,我就在想,是否是我哪里想错了?

而后我就查看了 Jquery Mobile 关于 taphold 的源码

看完源码后,我惊喜的发现,原来他也是利用 setTimeout 来实现的这一事件,证实个人想法是对的!

带着惊喜,我开始分析我思考的不足的地方。

最后我发现,原来是我没有作好对事件的监听

我只是单纯的绑定了 mousedownmouseup 两个事件,这是我在 JS 事件处理上的不足

完善实现

知道了问题以后,我就开始修改以前写的例子

采用 Jquery Mobile 库对事件的处理方式,来实现这个长按的功能,而且也根据自身的需求进行修改

在修改的过程当中,我发现了一个问题,就是当我长按一个按钮的时候,若是我移动鼠标,长按事件也会一直持续下去,而且放开鼠标也不会中止

在翻看 JS 事件的以后,我找到了 mouseleave 这个事件,就是当鼠标离开按钮以后,会触发这个事件,加上以后,问题也得己解决。

为了兼容移动设备,我加上了对 touchstarttouchendtouchcencel 几个事件的监听

原本也想加上 touchleave 事件,来处理触摸时用户移动到按钮外的状况,可是彷佛这个事件已经被废弃掉了:

This event was a proposal in an early version of the specification and has not been implemented. Do not rely on it. —— MDN

也尝试了使用 touchmove 事件来代替,可是彷佛会影响用户体验

由于添加了这个事件以后,就算是在按钮上触摸移动,也会触发 touchmove 事件

因此若是是用户误操做的话,也会停止长按操做。

不过,touch 事件并不会像 mouse 事件同样,触摸移动到按钮外以后再放开手指,事件仍是能够正常处理,并不会影响使用

最终代码

JS Code

var tapParams = {
    timer: {},
    element: {},
    tapStartTime: 0,
    type: 'increment'
};

function clearTapTimer() {
    clearTimeout(tapParams.timer);
}

function clearTapHandlers() {
    clearTapTimer();

    $(tapParams.element).unbind('mouseup', clearTapTimer)
        .unbind('mouseleave', clearTapHandlers);

    /* 移动设备 */
    $(tapParams.element).unbind('touchend', clearTapTimer)
        .unbind('touchcencel', clearTapHandlers);
}

function tapEvent(aEvent, aType) {

    /* 阻止默认事件并解除冒泡 */
    aEvent.preventDefault();
    aEvent.stopPropagation();

    tapParams = {
        element: aEvent.target,
        startTime: new Date().getTime() / 1000,
        type: aType
    };

    $(tapParams.element).bind('mouseup', clearTapTimer)
        .bind('mouseleave', clearTapHandlers);

    /* 移动设备 */
    $(tapParams.element).bind('touchend', clearTapTimer)
        .bind('touchcencel', clearTapHandlers);

    changeNumber();
}

function changeNumber() {

    var currentDate = new Date().getTime() / 1000;
    var intervalTime = currentDate - tapParams.startTime;

    /* 根据长按的时间改变数值变化幅度 */
    if (intervalTime < 1) {
        intervalTime = 0.5;
    }
    var secondCount = intervalTime * 10;
    if (intervalTime == 3) {
        secondCount = 50;
    }
    if (intervalTime >= 4) {
        secondCount = 100;
    }

    var numberElement = $('.number');
    var currentNumber = parseInt(numberElement.val());

    if (tapParams.type == 'increment') {
        currentNumber += 1;
    } else if (tapParams.type == 'decrement') {
        currentNumber -= 1;
    }

    numberElement.val(currentNumber <= 0 ? 1 : currentNumber);

    tapParams.timer = setTimeout('changeNumber()', 1000 / secondCount);
}

HTML Code

<div class="container">
    <div class="section">
        <div class="decrement" onmousedown="tapEvent(event, 'decrement')" ontouchstart="tapEvent(event, 'decrement')">-</div>
        <input class="number" value="1">
        <div class="increment" onmousedown="tapEvent(event, 'increment')" ontouchstart="tapEvent(event, 'increment')">+</div>
    </div>
</div>

CSS Code

.section {
    display: -webkit-flex;
    display: flex;
    -webkit-justify-content: center;
    justify-content: center;
    -webkit-flex-flow: row nowrap;
    flex-flow: row nowrap;
    -webkit-align-items: center;
    align-items: center;
    height: 30px;
    width: 130px;
    font-size: 16px;
}
.number {
    -webkit-flex: 1;
    flex: 1;
    width: 30px;
    height: 30px;
    border: 1px solid #000;
    display: inline-block;
    border-radius: 5px;
    margin: 0 10px;
    text-align: center;
}
.decrement, .increment {
    width: 30px;
    height: 30px;
    border: 1px solid #000;
    display: inline-block;
    border-radius: 5px;
    text-align: center;
    line-height: 28px;
    cursor: pointer;
    font-size: 20px;
}

效果展现

JS如何利用定时器实现长按事件

相关文章
相关标签/搜索