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如何利用定時器實現長按事件

相關文章
相關標籤/搜索