搖一搖事件
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與面向對象》
搖一搖事件