2021年6月5日 星期六

LimeJS : 由A的事件中去觸發B的事件

2021年6月5日 星期六

先說本篇的筆記重點:

  • 利用 dispatchEvent 可以觸發指定物件的某事件。
  • 利用 hitTest 可以偵測某個物件是否被按到了(它利用座標計算)。

對於 events 操作都是用仿作學習的,遇到問題時,才會去找資料看,很多地方都一知半解。之前在設計 CS Unplugged 的輔具時,曾經利用 lime.Button 設計了一個 checkBox 的開關,按下去時,會有個指示狀態的圓往左或往右跑,來顯示 On / Off 的狀態。今天應用在戳戳樂時,為了讓它能跟其它的按鈕都有個圓形的外框,於是在 checkBox 下方加了一個 lime.Circle 的元件。

按 checkBox 時,指示器當然會正常的往左或往右跑。但是如果按到背景的 lime.Circle 時,因為它不屬於 checkBox lime.Button 的一部份,當然是動也不動。

很單純的想,那就幫 lime.Circle 加上 mousedown 、touchstart events 的監聽程式,觸發時,再去觸發 lime.Button 的 mousedown ,就可以連動了。

如果是一般的物件,去呼叫 .click() 就好了,但這些 LimeJS 物件,並有有 .click() 可用啊!

試了半天,本來還在研究用 goog.events,試了:

  • goog.events.fireListener
  • goog.events.hasListener
  • goog.evnets.getListener
  • goog.events.getListeners

用 fireListener 可以觸發指定物件的某事件,它的語法:


fireListener( listener, eventObject )


它需要兩個參數, listener 可以用 getListeners 來找出來。看看它的語法


getListeners( obj, type, capture )


第一個參數是物件,第二個參數是哪一種 EVENT,本來以為它只要兩個參數就可以運作,結果都是傳回空的陣列。試了半天才將第三個參數(false / true)加上,順利取得 listener,可以給 fireListener 用。


var listener = goog.events.getListeners(target, 'mousedown', false);

goog.events.fireListener(listener[0], e);



後來才知道,其實直接用 dispatchEvent 更簡單:


goog.events.dispatchEvent(target, e);


不過前面兩種方法都是可以看到我的 checkBox 按鈕的部份有動一下,但是出現了錯誤訊息而卡住了:


Uncaught TypeError: this.setState is not a function
    at lime.Circle.<anonymous> (button.js:50)
    at lime.events.EventDispatcher.handleEvent (eventdispatcher.js:142)
    at lime.events.EventDispatcher.listener.<computed> [as __closure_events_fn_36391496] (events.js:978)
    at Object.goog.events.fireListener (events.js:741)
    at HTMLBodyElement.goog.events.handleBrowserEvent_ (events.js:862)
    at HTMLBodyElement.f (events.js:276)


裡面有個關鍵「 this.setState is not a function」,setState 是 lime.Button 中使用的,用來更換按鈕按下去跟彈起來的兩個狀態。

前兩個方法的第二個參數我都是直接把 lime.Circle 按下後的 e 直接傳給 lime.Button,而 e 中記錄的觸發目標(e.target)是 lime.Circle,lime.Circle 並沒有 setStat() 可使用啊!

所以照我的應用,無論是 fireListener 或是  dispatchEvent ,都不能直接把 lime.Circle 的 EVENT 物件傳給 lime.Button 用,要自己設定新的 EVENT 物件。改成這樣:


goog.events.dispatchEvent(t, {
type:'mousedown'
, target:target
});


不過新問題來了,出現了這樣的錯誤訊息:


button.js:32 Uncaught TypeError: e.swallow is not a function


很明顯的,還需要用到 swallow 這個 function,那就餵給它吧!改成:


goog.events.dispatchEvent(t, {
type:'mousedown'
, target:target 
, swallow: function(){}
});


這樣子果然都沒有錯誤訊息了。

不過在測試的時候發現,如果只按比較大的 lime.Circle ,可以正常運作;但是如果按到是放在它中央的 lime.Button 時,開關的動作會有兩次,那不就等於沒按一樣!

這個情形以前也會發生在疊在一起的兩個都監聽 mousedown 的物件,按完上面這個,下面的物件也跟著觸發了。過去都是加一個變數來控制能不能執行按下後的程序,並且在第一個執行完,利用 setTimeout 延遲把控制動作的變數設為 enable,實在麻煩!

今天再仔細研究了 lime.Button 的程序,它在 mousedown 中使用到了 hitTest 來檢測是否按到 target,終於知道它的用途了,把上面的程序再修改為:


if(!target.hitTest(e)) {
goog.events.dispatchEvent(t, {
type:'mousedown'
, target:target 
, swallow: function(){}
});
}


也是就在 lime.Circle 中檢查,當不是按到位於 target (lime.Button) 的範圍內時,才去觸發 target 的 mousedown,這樣就能避免 target 的 mousedown 被連續觸發了。



沒有留言:

張貼留言

 
雄::gsyan © 2009. Design by Pocket