1. 程式人生 > >搖一搖事件

搖一搖事件

llb 基本 src 算法 最小值 alt span ack list

html5新增了一個devicemotion的事件,可以使用手機的重力感應。如下代碼所示:

window.ondevicemotion = function(event){

var gravity = event.accelerationIncludingGravity;

console.log(gravity.x, gravity.y, gravity.z);

}

x,y,z表示三個方向的重力加速度,如下圖所示:

技術分享

x是手機短邊,y是長邊,z是和手機屏幕垂直的方向,當把手機平著放的時候,由於x、y和地平線平行,所以g(x) = g(y) = 0,而z和地平線垂直,所以g(z) = 9.8左右,同理當把手機豎著放的時候,g(x) = g(z) = 0,而g(y) = -9.8.

devicemotion事件會不斷地觸發,而且觸發得很快。

當我們把手機拿起來搖一搖的時候,這個場景應該是這樣的:

技術分享

y軸和x軸的變化範圍從-45o到+45o,即這個區間是:

delta = 9.8 * sin(45o) * 2 = 13.8

即只要x軸和y軸的g值變化超過13.8,我們就認為發生了搖一搖事件。

根據上面的分析,不難寫出以下的代碼:

const EMPTY_VALUE = 100;

const THREAD_HOLD = 13.8;

var minX = EMPTY_VALUE,

minY = EMPTY_VALUE;

window.ondevicemotion = function(event){

var gravity = event.accelerationIncludingGravity,

x = gravity.x,

y = gravity.y;

if(x < minX) minX = x;

if(y < minY) minY = y;

if(Math.abs(x - minX) > THREAD_HOLD &&

Math.abs(y - minY) > THREAD_HOLD){

console.log("shake");

var event = new CustomEvent("shake");

window.dispatchEvent(event);

minX = minY = EMPTY_VALUE;

}

}

window.addEventListener("shake", function(){

console.log("window shake callback was called");

});

用一個minX和minY記錄最小的值,每次devicemotion觸發的時候就判斷當前的g值與最小值的差值是否超過了閾值,如果是的話就創建一個CustomEvent的實例,然後disatch給window,window上兼聽的onshake事件就會觸發了。

現在拿起手機搖一搖,控制臺就會輸出:

技術分享

這樣就實現了一個搖一搖shake事件。還有一個問題就是:這個shake會不會很容易觸發,即使不是搖一搖操作它也觸發了?根據實驗上面代碼如果不搖不容易觸發shake,同時搖的時候比較容易觸發。如果太難觸發可以把閾值改小點。

當然判斷是否搖一搖的算法不止上面一個,你還可以想出其它更好的方法。

綜上,本文討論了怎麽去掉移動端click事件遲鈍的300ms延遲,怎麽實現一個快速響應的tap事件,怎麽封裝和觸發自定義事件,以及搖一搖的原理是怎麽樣的,怎麽實現一個搖一搖的shake事件。

相信閱讀了本文,你就知道了怎麽用一些基本事件進行組合觸發一些高級事件。通常把這些基本事件封裝起來,如上面用一個$Element的類,由它負責決定是否觸發tap,而高層的調用者不需要關心tap事件觸發的細節,這個$Element就相當於一個事件代理,或者也可以把tap當作一個門面。所以它是一個代理模式或者門面模式。更多設計模式可以查看本文《JS與面向對象》

搖一搖事件